16 经典问题解析二
1 析构函数调用顺序
-
【问题】当程序中存在多个对象时,如何确定这些对象的析构顺序?
- 对于栈对象和全局对象,类似于入栈和出栈的顺序,最后构造的对象被最先析构
- 堆对象的析构发生在使用
delete
的时候,与delete
的使用顺序相关
-
单个对象创建时构造函数的调用顺序
- 1.调用父类的构造函数
- 2.调用成员变量的构造函数(调用顺序与声明顺序相同)
- 3.调用类自身的构造函数
- 析构函数与对应构造函数的调用顺序相反
-
多个对象析构时,析构顺序与构造顺序相反
-
示例1:构造与析构顺序
-
Demo
#include <stdio.h> class Member { const char* ms; public: Member(const char* s) { printf("Member(const char* s): %s\n", s); ms = s; } ~Member() { printf("~Member(): %s\n", ms); } }; class Test { Member mA; Member mB; public: Test() : mB("mB"), mA("mA") { printf("Test()\n"); } ~Test() { printf("~Test()\n"); } }; Member gA("gA"); int main() { Test t; return 0; }
-
编译运行
Member(const char* s): gA Member(const char* s): mA Member(const char* s): mB Test() ~Test() ~Member(): mB ~Member(): mA ~Member(): gA
-
2 const 对象
-
【问题】
const
关键字能否修饰类的对象,如果可以,有什么特性?const
关键字能够修饰类的对象const
修饰的对象为只读对象- 只读对象的成员变量不允许被改变
- 只读变量是编译阶段的概念,运行时无效
-
const
成员函数的定义Type ClassName::function(Tyep p) const
类中的函数声明与实际函数定义中都必须带
const
关键字 -
C++ 中的
const
成员函数const
对象只能调用const
的成员函数const
成员函数中只能调用const
成员函数const
成员函数中不能直接改写成员变量的值
-
示例2:类的
const
函数-
Demo1:只读对象的成员变量不允许被改变
#include <stdio.h> class Test { int mi; public: int mj; Test(int i); Test(const Test& t); int getMi(); }; Test::Test(int i) { mi = i; } Test::Test(const Test& t) { } int Test::getMi() { return mi; } int main() { // 定义 const 对象 const Test t(1); t.mj = 1000; return 0; }
-
编译
test.cpp: In function ‘int main()’: test.cpp:31:10: error: assignment of member ‘Test::mj’ in read-only object t.mj = 1000; ^
-
Demo2:
const
对象只能调用const
的成员函数#include <stdio.h> class Test { int mi; public: int mj; Test(int i); Test(const Test& t); int getMi(); }; Test::Test(int i) { mi = i; } Test::Test(const Test& t) { } int Test::getMi() { return mi; } int main() { const Test t(1); printf("t.getMi() = %d\n",t.getMi()); // const对象不能调用普通成员函数 return 0; }
-
编译
test.cpp: In function ‘int main()’: test.cpp:31:39: error: passing ‘const Test’ as ‘this’ argument discards qualifiers [-fpermissive] printf("t.getMi() = %d\n",t.getMi()); ^ test.cpp:23:5: note: in call to ‘int Test::getMi()’ int Test::getMi() ^
-
3 类成员
-
【问题】成员函数和成员变量都是隶属于具体对象的么?
-
从对象对象的角度
- 对象由属性(成员变量)和方法(成员函数)构成
-
从程序运行的角度
- 对象由数据和函数构成
- 数据可以位于栈,堆和全局数据区
- 函数只能位于代码段
- 对象由数据和函数构成
-
结论
- 每一个对象拥有自己独立的属性(成员变量)
- 所有的对象共享类的方法(成员函数)
- 类的方法能够直接访问对象的属性
- 类的方法中的隐藏参数
this
指针(常量指针,始终指向调用当前函数的对象)用于指代当前对象
-
示例3
-
Demo
#include <stdio.h> class Test { int mi; public: int mj; Test(int i); Test(const Test& t); int getMi(); void print(); }; Test::Test(int i) { mi = i; } Test::Test(const Test& t) { mi = t.mi; //为什么拷贝构造函数可以访问对象t的private成员变量mi? =>封装是编译期的概念,是针对类型而非对象的,在类的成员函数中可以访问同类型实例对象的私有成员变量 } int Test::getMi() { return mi; } void Test::print() { printf("this = %p\n", this); } int main() { Test t1(1); Test t2(2); Test t3(3); printf("t1.getMi() = %d\n", t1.getMi()); // t1.getMi() = 1 printf("&t1 = %p\n", &t1); // &t1 = 0xbf975fd4 t1.print(); // this = 0xbf975fd4 printf("t2.getMi() = %d\n", t2.getMi()); // t2.getMi() = 2 printf("&t2 = %p\n", &t2); // &t2 = 0xbf975fdc t2.print(); // this = 0xbf975fdc printf("t3.getMi() = %d\n", t3.getMi()); // t3.getMi() = 3 printf("&t3 = %p\n", &t3); // &t3 = 0xbf975fe4 t3.print(); // this = 0xbf975fe4 return 0; }
-