C++核心编程 4 类和对象 - C++对象模型和this指针(3)


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

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

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

/*class person
{
    
}; 
void test1()
{
    person p;
    //空对象占用内存空间为: 0 ? 4 ? 1 ?
    cout << "size of p = " << sizeof(p) << endl;
    //size of p = 1
    //C++编译器会给每个空对象也分配一个字节的空间,是为了区分空对象占内存的位置
    //每个空对象也应该有个独一无二的内存地址
}*/

//成员函数和成员变量是分开存储的
class person
{
    int m_a;                    //非静态成员变量    属于类的对象上
    static int m_b;             //静态成员变量      不属于类对象上
    void func() {}              //非静态成员函数    不属于类对象上
    static void func2()  {}     //静态成员函数      不属于类对象上
}; int person::m_b = 0;

void test1()
{
    person p;
    //此时类内有对象占用的内存空间为:  0?  4?  1?
    cout << "size of p = " << sizeof(p) << endl;
    //size of p = 4
}
int main()
{
    test1();
    system("pause");
    return 0;
}

 4.3.2 this指针概念

通过4.3.1了解到在C++中成员变量和成员函数是分开存储的,每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会公用同一块代码,那么问题是:这一块代码是如何区分哪个对象调用自己的呢?

c++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象

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

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

this指针的用途:

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

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

class Person
{
public:
    Person(int age)
    {   
        //m_age = age;  //要么形参与成员变量不同名  要么用this
        
        //this指针指向的是被调用的成员函数所属的对象
        this->age = age;
    }
    
    //int m_age;
    int age;

    //void PersonAddAge(Person p)
    Person& PersonAddAge(Person p)   //因为return了*this 所以不能用void,而是以引用的方式返回,返回的是这个对象的本身,如果不带引用,执行完一次p2.PersonAddAge(p1)函数后,再执行一次会将之前的覆盖掉,返回的就不是这个对象本身,而是拷贝出来的副本
    {
        this->age += p.age;
        return *this;   //返回类型为*this等同于返回值类型为p2  this指向p2的指针,而*this指向的就是p2这个对象的本体   刚才没加爽,现在让你加爽
    }

}; 

//1、解决名称冲突
void test1()
{
    Person p1(18);
    //cout << "p1 age = " << p1.m_age << endl;
    cout << "p1 age = " << p1.age << endl;
}

//2、返回对象本身用 *this
void test2()
{
    Person p1(10);

    Person p2(10);

    //p2.PersonAddAge(p1);  //p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1)  没加爽,想再加几次p1的年龄 这样不行 因为 p2.PersonAddAge(p1)返回值类型为p2,而PersonAddAge(Person p)函数的返回值类型为void。类型不同,不能连续调用(链式调用 
    //链式编程思想
    p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);  //刚才没加爽,现在让你加爽
    cout << "p2 age = " << p2.age << endl;

}
int main()
{
    //test1();
    test2();
    system("pause");
    return 0;
}

4.3.3空指针访问成员函数

c++中空指针也是可以调用成员函数的,但是要注意到有没有用到this指针,如果用到了this指针,需要加以判断保证代码的健壮性

class Person
{
public:
    
    void showClassName()
    {
        cout << "this is person class" << endl;

    }

    void showPersonAge()
    {
        //报错原因是因为传入的指针为 NULL
        if (this == NULL)
        {
            return;
        }
        cout << "age = " << m_Age << endl;  //实际上是 cout << "age = " << this->m_Age << endl; 因为Person* p = NULL,这里的this也就默认成了空指针,这里的空指针this是访问不了函数里的成员m_Age的
    }

    int m_Age;

}; 

void test1()
{
    Person* p = NULL;

    p->showClassName();
    p->showPersonAge();
}

int main()
{
    test1();
    system("pause");
    return 0;
}

4.3.4 const修饰成员函数

常函数

1、成员函数后加const后,称这个函数是常函数

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

3、成员属性声明时加关键字mutable后,在常函数中方可进行修改

常对象

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

2、常对象只能调用常函数

//常函数
class Person
{
public:
    void showPerson() const   //不加const的话,在函数体内部可以修改m_A;加上后 等同于Person * const this
    //在成员函数后面加上const,修饰的是this指针,让指针指向的值也不可以修改
    //this指针的本质是指针常量  指针的指向是不可以修改的
    {
        this->m_B = 100;
        //this->m_A = 100; //m_A = 100;
        this = NULL;   //this指针是不可以修改指针的指向的
    }

    void func()
    {
        m_A = 100;
    }

    int m_A;
    mutable int m_B;   //特殊变量,即使在常函数中,也可以修改这个值
};
void test1()
{
    Person p;
    p.showPerson();

}

//常对象
void test2()
{
    const Person p;  //在对象前加const,变为常对象
    p.m_A = 100;
    p.m_B = 100;     //m_B是特殊变量,在常对象下也可以修改这个值

    //常对象只能调用常函数
    p.showPerson();
    p.func();    //常对象只能调用常函数

}


int main()
{
    system("paluse");
    return 0;
}