4.3 C++对象模型和this指针

4.3 C++对象模型和this指针

4.3.1 成员变量和成员函数分开存储

在C++中,类内的成员变量和成员函数分开存储

只有非静态成员变量才属于类的对象上

c 复制代码
#include <iostream>

class Person {
public:
	Person() {
		mA = 0;
	} 
	//非静态成员变量占对象空间
	int mA;
	//静态成员变量不占对象空间
	static int mB;
	//函数也不占对象空间,所有函数共享一个函数实例
	void func() {
		std::cout << "mA:" << this->mA << std::endl;
	} 

    //静态成员函数也不占对象空间
	static void sfunc() {
        
	}
};

int main() {
    
    //实例化一个对象为p1
    Person p1;

	std::cout << "Person:"<<sizeof(Person) << std::endl;
    std::cout << "p1:" << sizeof(p1) << std::endl;
    
	
    
	return 0;
}

运行结果如下:

4.3.2 this指针概念

通过4.3.1我们知道在C++中成员变量和成员函数是分开存储的

每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码

那么问题是:这一块代码是如何区分那个对象调用自己的呢?

c++通过提供特殊的对象指针,this指针,解决上述问题。

this指针指向被调用的成员函数所属的对象

this指针是隐含每一个非静态成员函数内的一种指针

this指针不需要定义,直接使用即可

this指针是一个常量指针,可以看做const type * this ,指针的指向不能修改,this = NULL这样是错的。

this指针的用途:

当形参和成员变量同名时,可用this指针来区分

在类的非静态成员函数中返回对象本身,可使用return *this

c 复制代码
#include <iostream>

class Person {
public:
	Person(int age) {
        //1 使用this区分形参和成员变量
		this->age = age;
	} 
	
	Person& PersonAddPerson(Person p) {

		this->age += p.age;
        //2 返回对象本身,this为指针,所以加上*
        return *this;
	} 



    //定义一个成员变量,属性为public
    int age;
};


void test01()
{   
    //实例化一个对象为p1,会调用有参构造函数
    Person p1(10);
    //打印p1.age的结果
    std::cout << "p1.age:" << p1.age << std::endl;

    //实例化一个对象为p2
    Person p2(12);
    //p2.PersonAddPerson(p1)这是使用p2对象调用成员函数PersonAddPerson(p1),
    //成员函数返回值是对象p2,然后再次调用成员函数
    p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);

    std::cout << "p2.age:" << p2.age << std::endl;

}

int main() {
    
   
    test01();
	
    
	return 0;
}

运行结果如下:

c 复制代码
#include <iostream>

class MyClass {
public:
    void printAddress() {
        std::cout << "Address of the current object: " << this << std::endl;
    }

    void modifyObject() {
        // 下面的语句是非法的,会导致编译错误
        // this = nullptr;  // Error: assignment of read-only parameter 'this'
        
        // 修改成员变量是合法的
        data = 42;
    }

private:
    int data;
};

int main() {
    MyClass obj;

    // 调用成员函数,显示对象地址
    obj.printAddress();

    // 调用修改对象的函数
    obj.modifyObject();

    return 0;
}
4.3.3 空指针访问成员函数

C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针

如果用到this指针,需要加以判断保证代码的健壮性

示例:

c 复制代码
#include <iostream>

class Person {
public:
	void ShowClassName() {
        std::cout << "Person类" << std::endl;
	} 
	
	void ShowPerson() {
        if(this == NULL)
            return ;

        std::cout << "age:" << age << std::endl;
	} 


    int age;

};


void test01()
{   
    //创建一个对象指针
    Person* p1 = NULL;
    //使用对象指针调用成员函数
    p1->ShowClassName();
    //使用对象指针调用成员函数,成员函数使用了this指针,空对象指针就使用不了   
    p1->ShowPerson();

}

int main() {
    
   
    test01();
	
    
	return 0;
}

执行结果如下:

成员函数去掉this判断部分

c 复制代码
#include <iostream>

class Person {
public:
	void ShowClassName() {
        std::cout << "Person类" << std::endl;
	} 
	
	void ShowPerson() {
        /*if(this == NULL)
            return ;
        */
        std::cout << "age:" << age << std::endl;
	} 


    int age;

};


void test01()
{   
    //创建一个对象指针
    Person* p1 = NULL;
    //使用对象指针调用成员函数
    p1->ShowClassName();
    //使用对象指针调用成员函数,成员函数使用了this指针,空对象指针就使用不了
    
    p1->ShowPerson();

}

int main() {
    
   
    test01();
	
    
	return 0;
}

再次编译执行结果如下

对于上面出现的错误做一个解释,

代码中,如果去掉了 if(this == NULL) 的检查,并试图在一个空指针上调用 ShowPerson 函数,程序会尝试通过一个空指针来访问 age 成员变量。对空指针进行解引用是一种未定义的行为,通常会导致段错误。

具体步骤如下:

  1. 声明一个空指针,例如 Person* nullPointer = nullptr;
  2. 尝试在这个空指针上调用一个成员函数:nullPointer->ShowPerson();
  3. ShowPerson 函数内部,尝试通过 this->age 访问 age 成员变量。
  4. 由于 this 是一个空指针,尝试访问 this->age 会导致段错误。
4.3.4 const修饰成员函数

常函数:

成员函数后加const后我们称为这个函数为常函数

常函数内不可以修改成员属性

成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象:

声明对象前加const称该对象为常对象

常对象只能调用常函数

const修饰成员函数

c 复制代码
#include <iostream>

class Person {
public:
    //默认构造函数
	Person() {
        p_a = 0;
        p_b = 0;
	} 
	
	void ShowPerson() {
        //隐含在每个成员函数内部都有一个this指针,this是一个常量指针
        //this = NULL; 常量指针的内容不能修改
        this->p_a = 10;//对于常量指针的指向的内容可以修改       
	} 

    void ShowPerson2() const {
        //隐含在每个成员函数内部都有一个this指针,this是一个常量指针
        //this = NULL; 常量指针的内容不能修改

        //const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量
        //this->p_a = 20;

        //p_b变量被mutable修饰,可以修改
        this->p_b = 100;

        //常函数中变量不能修改
        //p_a = 12;
        //使用mutable修改的变量可以修改
        p_b = 22;       
	} 

public:
    int p_a;
    mutable int p_b;

};


void test01()
{   
    //创建一个对象,会调用默认构造函数
    Person p1;
    //查看变量p_a和p_b的值,调用构造函数后值都为0
    std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;

    //使用对象调用成员函数
    p1.ShowPerson();
    //查看此时变量p_a和p_b的值,p_a会变为10,p_b为0
    std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;

    //使用对象调用常量成员函数
    p1.ShowPerson2();
    //查看此时变量p_a和p_b的值,p_a会为10,p_b为22
    std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;

}

int main() {
    
   
    test01();
	
    
	return 0;
}

运行结果如下图:

const修饰对象

c 复制代码
#include <iostream>

class Person {
public:
    //默认构造函数
	Person() {
        p_a = 0;
        p_b = 0;
	} 
	
	void ShowPerson() {
        //隐含在每个成员函数内部都有一个this指针,this是一个常量指针
        //this = NULL; 常量指针的内容不能修改
        this->p_a = 10;//对于常量指针的指向的内容可以修改       
	} 

    void ShowPerson2() const {
        //隐含在每个成员函数内部都有一个this指针,this是一个常量指针
        //this = NULL; 常量指针的内容不能修改

        //const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量
        //this->p_a = 20;

        //p_b变量被mutable修饰,可以修改
        this->p_b = 100;

        //常函数中变量不能修改
        //p_a = 12;
        //使用mutable修改的变量可以修改
        p_b = 22;       
	} 

public:
    int p_a;
    mutable int p_b;

};


void test01()
{   
    //创建一个常量对象p1,会调用默认构造函数
    const Person p1;
    
    //1 常量对象不能修改成员变量的值
    
    //p1.p_a = 33;
    //可以修改被mutable修饰的变量值
    p1.p_b = 11;
    //可以访问成员变量的值
    std::cout << "p_a:" << p1.p_a << std::endl;
    std::cout << "p_b:" << p1.p_b << std::endl;

    //2 常量对象访问成员函数,只能访问常函数
    
    //ShowPerson是非常函数,常量对象不能访问
    //p1.ShowPerson();
    //访问常函数
    p1.ShowPerson2();
    std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;



}

int main() {
    
    test01();
	
	return 0;
}

运行结果如下:

相关推荐
一点媛艺1 小时前
Kotlin函数由易到难
开发语言·python·kotlin
姑苏风1 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
奋斗的小花生2 小时前
c++ 多态性
开发语言·c++
魔道不误砍柴功2 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
闲晨2 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程2 小时前
一个例子来说明Ada语言的实时性支持
开发语言·ada
UestcXiye3 小时前
《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列
c++·计算机网络·ip·tcp
Chrikk3 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*3 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue3 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang