C++ 面向对象模型初探(8)

2022-06-20  本文已影响0人  maskerII

1. 成员变量和函数的存储

c++中“数据”和“处理数据的操作(函数)”是分开存储的

空类的大小是1,不是0

// 1. 空类的大小是1,不是0
class Maker
{
};

void test01()
{
    cout << sizeof(Maker) << endl; // 1

    Maker *m = new Maker[20]; // 为什么空类是1,因为编译器从内存更好区分对象
}

类的成员函数、静态成员函数、静态成员变量不占用类的大小

class Maker2
{
public:
public:
    // 类的成员函数 不占用类的大小
    void func()
    {
    }
    // 类的静态成员函数 不占用类的大小
    static void func2()
    {
    }
    // 类的静态成员变量 不占用类的大小
    static int a;
};

void test02()
{
    cout << sizeof(Maker2) << endl;
}

普通成员 占用类的大小

// 3. 普通成员 占用类的大小
// 4. 类的成员中,成员函数和成员变量是分开存储的
class Maker3
{
public:
    // 类的成员函数和成员变量是分开存储的,那为什么类的成员函数可以访问成员变量?
    // 编译器内部把成员变量的空间的指针 传入成员函数中 void func(this *p)
    void func()
    {
        b = 20;
        cout << b << endl;
    }
    static void func2()
    {
    }
    static int a;
    int b; // 普通成员 暂用类的大小 4 字节
    int c; // 4 字节
};

int Maker3::a = 100;

void test03()
{
    cout << sizeof(Maker3) << endl; // 8
    Maker3 m;
    m.func();
}

总结:
1.空类的大小是1,不是0
2.类的成员函数、静态成员函数、静态成员变量不占用类的大小
3.普通成员 占用类的大小
4.类的成员中,成员函数和成员变量是分开存储的

2. this指针

c++的数据和操作也是分开存储,并且每一个非内联成员函数(non-inline member function)只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码

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

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

c++规定,this指针是隐含在对象成员函数内的一种指针。当一个对象被创建后,它的每一个成员函数都含有一个系统自动生成的隐含指针this,用以保存这个对象的地址,也就是说虽然我们没有写上this指针,编译器在编译的时候也是会加上的。因此this也称为“指向本对象的指针”,this指针并不是对象的一部分,不会影响sizeof(对象)的结果。
  
this指针是C++实现封装的一种机制,它将对象和该对象调用的成员函数连接在一起,在外部看来,每一个对象都拥有自己的函数成员。一般情况下,并不写this,而是让系统进行默认设置。

this指针永远指向当前对象

成员函数通过this指针即可知道操作的是那个对象的数据。this指针是一种隐含指针,它隐含于每个类的非静态成员函数中。this指针无需定义,直接使用即可。

注意:静态成员函数内部没有this指针,静态成员函数不能操作非静态成员变量。

2.1 this指针的作用

class Maker2
{
public:
    int id;

public:
    // 1.当形参名和成员变量名相同时,用this指针区分
    Maker2(int id)
    {
        this->id = id;
    }

    // 2. 返回对象的本身
    Maker2 &getMaker2()
    {
        return *this; // 运算符重载时有用
    }
};

2.2 this指针拓展

this指针指向的空间有没有存储静态成员变量?
没有,静态成员变量是属于类,所有对象共有的

class Maker3
{
public:
    static void func()
    {
        // this->a = 200; //报错
    }

public:
    static int a;
};

int Maker3::a = 10;

void test02()
{
    Maker3 m;
    m.func();

}

this指针的指向可以改变吗?
this指针是指向对象的存储空间,是不可以改变的,也就是说this是Class* const this

总结:
1.每个对象都有一个隐藏的this指针,但不属于对象,是编译器添加的
2.编译器会把this指针传入成员函数内
3.this指针永远指向当前对象
4.this指针的作用:1)当形参名和成员变量名相同时,用this指针区分。2)返回对象的本身
5.this指针指向的空间没有存储静态成员变量
6.this指针的指向不能改变

3. const修饰成员函数(常函数)

用const修饰的成员函数被称为常函数

class Maker
{
public:
    Maker(int id, int age)
    {
        this->id = id;
        this->age = age;
        score = 100;
    }
    // 常函数
    // 1. 在函数的()后面加上const,就是常函数
    void printMaker() const
    {
        // id = 100; // 2.常函数体内不能修改普通成员变量
        // 3. const修饰的是this指针指向的空间中的变量,不能改变
        // Maker *const this;
        // const Maker*const this; 这是常函数修饰的
        score = 200; // 4.mutable 修饰的成员变量在常函数中可以修改
        cout << "score = " << score << endl;
    }

public:
    int id;
    int age;
    mutable int score; // mutable 修饰的成员变量
};

4. const修饰对象(常对象)


class Maker
{
public:
    Maker(int id, int age)
    {
        this->id = id;
        this->age = age;
        score = 100;
    }
    void func()
    {
        cout << "普通成员函数 func() 调用" << endl;
    }

    void func2() const
    {
        cout << "常函数 func2() 调用" << endl;
    }

public:
    int id;
    int age;
    mutable int score;
};

// 常对象
void test()
{

    Maker m1(1, 18);
    m1.id = 100;
    m1.func();
    m1.func2(); // 普通对象也可以调用常函数

    // 1.在数据类型前面加上const,让对象成为常对象
    const Maker m2(1, 18);
    // m2.id = 100;// 常对象不能修改普通成员变量
    // m2.func(); // 常对象不能调用普通成员函数
    m2.func2();             // 2.常对象可以调用常函数
    cout << m2.age << endl; // 常对象可访问 const 或非 const 数据成员
    m2.score = 200;         // 3.常对象可以修改mutable修饰的成员变量
}
上一篇下一篇

猜你喜欢

热点阅读