四、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; }
#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; }
/* 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; }
/* 常函数: 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; }