美文网首页
C++ 面向对象模型初探(8)

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

作者: maskerII | 来源:发表于2022-06-20 14:05 被阅读0次

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

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

    • c++中的非静态数据成员直接内含在类对象中,就像c struct一样。
    • 成员函数(member function)虽然内含在class声明之内,却不出现在对象中。
    • 每一个非内联成员函数(non-inline member function)只会诞生一份函数实例.

    空类的大小是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指针的作用

    • 当形参名和成员变量名相同时,用this指针区分
    • 在类的非静态成员函数中返回对象本身,可使用return *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修饰的成员函数被称为常函数

    • 用const修饰的成员函数时,const修饰this指针指向的内存区域,成员函数体内不可以修改本类中的任何普通成员变量
    • 当成员变量类型用mutable修饰时例外
    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修饰对象(常对象)

    • 常对象只能调用const的成员函数
    • 常对象可访问 const 或非 const 数据成员,不能修改,除非成员用mutable修饰
    
    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修饰的成员变量
    }
    

    相关文章

      网友评论

          本文标题:C++ 面向对象模型初探(8)

          本文链接:https://www.haomeiwen.com/subject/vkljvrtx.html