四、C++面向对象模型初探

一、类的大小

成员函数和成员变量是分开存储的
空类的大小是1
只有非晶态成员变量才属于对象本身

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Person
{

};

void test01()
{
    cout << "空类的大小是: " << sizeof(Person) << endl; // 空类的大小是: 1
}

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

/*
    空类的大小是 1 , 每个实例的对象都有独一无二的地址, char 维护这个地址
*/
// 只有非静态成员变量,才属于对象身上
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Person
{
public:
    int a;      // 非静态成员,属于对象身上
    void func() {} // 成员属性和成员函数是分开存储的, 非静态成员函数不属于对象身上
    static int b; // 静态成员变量也不属于对象身上
    static void fun() {}  // 静态成员函数也不属于对象身上
    double c;  // 存在字节对齐
};

void test01()
{
    cout << "大小是: " << sizeof(Person) << endl; // 大小是: 16
}

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

 

二、this指针

2.1 了解this的存在

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

// this 指针指向被调用的成员函数所属的对象
class Person
{
public:
    int a;      
    void func()  // 本质上是这样的: void func(Person* this)
    {
    } 

};

void test()
{
    Person p1;
    p1.func(); // 编译器会自动将我们加入一个this指针, Person* this
}


int main()
{
    return EXIT_SUCCESS;
}

 

2.2 this指针的使用

/* 
    1. this 指针永远指向被调用的成员函数所属的对象,
    2. 可以解决命名冲突
    3. this指针可以指向对象本体
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Person
{
public:
    Person(int age)
    {
        // age = age;  直接这样写是不行的, age不清楚具体的是什么, 输出的年龄就是随机数
        this->age = age; // this 指针指向我们传输的对象, 所以this可以解决命名冲突
    }

    // 对比年龄
    void compareAge(Person &p)
    {
        if (this->age == p.age)  // 不写this也行,默认会自动添加
        {
            cout << "年龄相等" << endl;
        }
        else
        {
            cout << "年龄不相等" << endl;
        }
    }

    // 年龄相加
    Person& PlusAge(Person &p)  // 必须要加 &, 如果不加上&引用,返回的是*this看起来是自身,但是是Person类型,是值的方式返回,相当于是一个拷贝构造函数调用,以值的方式进行拷贝了一个本体数据返回回来了。所以链式编程一定要返回引用
    {
        this->age += p.age;
        return *this;  // this 是一个指针, *this就是指向对象本体
    }
    int age;
};

void test()
{
    Person p1(10);
    cout << "p1的年龄是 " << p1.age << endl; // p1的年龄是 10
    Person p2(10);
    p1.compareAge(p2);  //  "年龄相等"
    p1.PlusAge(p2);
    cout << "p1的年龄是 " << p1.age << endl; // p1的年龄是 20

    // p1.PlusAge(p2).PlusAge(p2);  p1.PlusAge(p2)返回的是 void,所以继续PlusAge(p2)是不行的,想要可以,必须要返回 Person 对象
    p1.PlusAge(p2).PlusAge(p2);  // 链式编程
    cout << "p1的年龄是 " << p1.age << endl; // p1的年龄是 40
}


int main()
{
    test();
    return EXIT_SUCCESS;
}

三、空指针访问成员函数

/*
    1. 如果成员函数没有用到this,那么空指针可以直接访问
    2. 如果成员函数用到了this指针,不能直接访问,就要加入if判断来处理
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;


class Person
{
public:
    void show()
    {
        cout << "Peson show" << endl;
    }
    void showAge()
    {
        if (this == NULL)  // 为了防止this是空指针,所以一般会加入判断
        {
            return;
        }
        cout << Age << endl;
    }
    int Age;
};

void test()
{
    Person *p = NULL;
    p->show();// 空指针可以访问, 因为相当于传输了一个 this,但是调用这个函数并没有用到this
    // p->showAge();// 错误空指针不可以访问, 传输了this指针,并且用到了this指针,但是this指针是指向空指针的,所以不能访问,一般会加入一个判断来处理
}


int main()
{
    test();
    return EXIT_SUCCESS;
}

 

四、const与常函数和常对象

/* 
常函数:
    void test() const
    {

    }
常函数内不能修改 this指针指向的值


常对象:
    在对象前加入 const修饰 const Person p1;
    常对象不可以调用普通成员函数,只能调用常函数
    用 mutable 修饰的成员变量是在常函数可以修改
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;


class Person
{
public:
    Person()
    {
        // 构造中修改属性
        // this指针永远都会指向自身的本体,也就是 Person * const this
        // this = NULL; this指向的 const,所以不能修改指针指向的对象,如果需要将指针指向的值不能修改,那么就应该是 const Person * const this了
        this->A = 0;
        this->B = 0;
    }
    void showInfo()
    {

        cout << "A = " << this->A << endl; // 这样能访问到A的值,但是也能修改A的值,所以为了不能修改A的值,就需要加入 const,具体见下面的函数
        cout << "B = " << this->B << endl;
    }
    void showAB() const  // 常函数,不允许修改指针指向的值
    {
        // this->A = 100;  const修饰了this之后, 就不能修改this指向的值了

        // 但是如果就算是常函数,还是想执意要修改值,就需要在成员变量之前加入 mutable
        this->B = 200;
        cout << "A = " << this->A << endl; 
        cout << "B = " << this->B << endl;
    }
    void showA()
    {
        this->A = 400;
    }

    int A;
    mutable int B;
};

void test()
{
    Person p1;
    p1.showInfo();
    p1.showAB();
    p1.A = 100;  // 这样是可以

    // 常对象, 不允许修饰属性
    const Person p2;
    // p2.A = 100; 这样操作就会报错了, A不能修改, 但是可以读
    cout << "p2.A = " << p2.A << endl;
    // 常对象不可以调用普通成员函数,只能调用常函数
    // p2.showA();  showA方法中修改了A的值,所以也不能调用
    // p2.showInfo(); 也不能调用
    p2.showAB();  // 没有问题
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

posted on 2022-03-14 20:27  软饭攻城狮  阅读(10)  评论(0编辑  收藏  举报

导航