1 #include <iostream>
2 #include <cstdio>
3 #include <cstdlib>
4 #include <cstring>
5 using namespace std;
6
7 #define ll long long
8
9 const int maxn=1e5+10;
10
11 class A {
12 public:
13 A() {
14 cout << "build A" << endl;
15 }
16 virtual ~A() {
17 cout << "delete A" << endl;
18 }
19 virtual void work() {
20 cout << "work A" << endl;
21 }
22 };
23
24 class B: public A {
25 public:
26 B() {
27 cout << "build B" << endl;
28 }
29 ~B() {
30 cout << "delete B" << endl;
31 }
32 virtual void work() override {
33 cout << "work B" << endl;
34 }
35 };
36
37 class C {
38 public:
39 C() {
40 cout << "build C" << endl;
41 }
42 virtual ~C() {
43 cout << "delete C" << endl;
44 }
45 virtual void work() {
46 cout << "work C" << endl;
47 }
48 };
49
50 class D: public C {
51 public:
52 D() {
53 cout << "build D" << endl;
54 }
55 ~D() {
56 cout << "delete D" << endl;
57 }
58 virtual void work() override {
59 cout << "work D" << endl;
60 }
61 void init() {
62 memset(a, 0, sizeof(a));
63 }
64 private:
65 int a[1000];
66 };
67
68 int main()
69 {
70 cout << "test1:" << endl;
71 A * obj1 = new B();
72 obj1 -> work();
73 delete obj1;
74 obj1 = nullptr;
75 cout << endl;
76 /*
77 build A
78 build B
79 work B
80 delete B
81 delete A
82 */
83
84 /*
85 如果class A析构函数不写成虚函数
86 build A
87 build B
88 work B
89 delete A
90 */
91
92 cout << "test2:" << endl;
93 A * obj2 = (A*)new B();
94 obj2 -> work();
95 delete obj2;
96 obj2 = nullptr;
97 cout << endl;
98 //和上面一样的结果
99
100 //wrong 编译的时候
101 /*
102 B * obj3 = new A();
103 obj3 -> work();
104 delete obj3;
105 obj3 = nullptr;
106 */
107
108 cout << "test3:" << endl;
109 B * obj4 = (B*)new A();
110 obj4 -> work();
111 delete obj4;
112 obj4 = nullptr;
113 cout << endl;
114 /*
115 build A
116 work A
117 delete A
118 */
119
120 cout << "test4:" << endl;
121 C * obj5 = new D();
122 obj5 -> work();
123 delete obj5;
124 obj5 = nullptr;
125 cout << endl;
126 /*
127 build C
128 build D
129 work D
130 delete D
131 delete C
132 */
133
134 cout << "test5:" << endl;
135 D * obj6 = (D*)new C();
136 obj6 -> work();
137 //obj6 -> init(); //运行时报错
138 delete obj6;
139 obj6 = nullptr;
140 cout << endl;
141 /*
142 build C
143 work C
144 delete C
145 */
146
147 return 0;
148 }
1 #include <iostream>
2 #include <cstdio>
3 #include <cstdlib>
4 #include <cstring>
5 using namespace std;
6
7 #define ll long long
8
9 const int maxn=1e5+10;
10
11 class A {
12 public:
13 A() {
14 cout << "build A" << endl;
15 }
16 virtual ~A() {
17 cout << "delete A" << endl;
18 }
19 virtual void work() {
20 cout << "work A" << endl;
21 }
22 };
23
24 class B: public A {
25 public:
26 B() {
27 cout << "build B" << endl;
28 }
29 ~B() {
30 cout << "delete B" << endl;
31 }
32 virtual void work() override {
33 cout << "work B" << endl;
34 }
35 };
36
37 class C {
38 public:
39 C() {
40 cout << "build C" << endl;
41 }
42 virtual ~C() {
43 cout << "delete C" << endl;
44 }
45 virtual void work() {
46 cout << "work C" << endl;
47 }
48 };
49
50 class D: public C {
51 public:
52 D() {
53 cout << "build D" << endl;
54 }
55 ~D() {
56 cout << "delete D" << endl;
57 }
58 virtual void work() override {
59 cout << "work D" << endl;
60 }
61 void init() {
62 memset(a, 0, sizeof(a));
63 }
64 private:
65 int a[1000];
66 };
67
68 int main()
69 {
70 cout << "test1:" << endl;
71 A * obj1 = new B();
72 obj1 -> work();
73 delete obj1;
74 obj1 = nullptr;
75 cout << endl;
76 /*
77 build A
78 build B
79 work B
80 delete B
81 delete A
82 */
83
84 /*
85 如果class A析构函数不写成虚函数
86 build A
87 build B
88 work B
89 delete A
90 */
91
92 cout << "test2:" << endl;
93 A * obj2 = (A*)new B();
94 obj2 -> work();
95 delete obj2;
96 obj2 = nullptr;
97 cout << endl;
98 //和上面一样的结果
99
100 //wrong 编译的时候
101 /*
102 B * obj3 = new A();
103 obj3 -> work();
104 delete obj3;
105 obj3 = nullptr;
106 */
107
108 cout << "test3:" << endl;
109 B * obj4 = (B*)new A();
110 obj4 -> work();
111 delete obj4;
112 obj4 = nullptr;
113 cout << endl;
114 /*
115 build A
116 work A
117 delete A
118 */
119
120 cout << "test4:" << endl;
121 C * obj5 = new D();
122 obj5 -> work();
123 delete obj5;
124 obj5 = nullptr;
125 cout << endl;
126 /*
127 build C
128 build D
129 work D
130 delete D
131 delete C
132 */
133
134 cout << "test5:" << endl;
135 D * obj6 = (D*)new C();
136 obj6 -> work();
137 //obj6 -> init(); //运行时报错
138 delete obj6;
139 obj6 = nullptr;
140 cout << endl;
141 /*
142 build C
143 work C
144 delete C
145 */
146
147 return 0;
148 }
这段代码主要展示了 C++ 中类的继承、多态、虚函数以及对象的创建与销毁过程,我们来逐一分析各个测试用例的输出结果:
A * obj1 = new B();
obj1 -> work();
delete obj1;
- 当创建
B对象时,会先调用父类A的构造函数,再调用B自身的构造函数,因此输出build A和build B
work()是虚函数,通过基类指针调用时会执行实际指向对象(B)的work()方法,因此输出work B
A的析构函数是虚函数,删除基类指针时会先调用派生类B的析构函数,再调用基类A的析构函数,因此输出delete B和delete A
如果A的析构函数不是虚函数,删除基类指针时只会调用基类A的析构函数,导致B的析构函数不会被执行,这就是为什么需要将基类析构函数声明为虚函数的原因。
这里的强制类型转换是多余的,因为B是A的派生类,B*可以隐式转换为A*。所以这段代码的行为和 test1 完全相同,输出结果也一样。
- 这里创建的是
A对象,所以只调用A的构造函数:build A
- 虽然通过强制类型转换将
A*转为B*,但实际对象还是A,所以work()调用的是A的版本:work A
- 删除时,由于实际对象是
A,所以只调用A的析构函数:delete A
这种转换是不安全的,因为A对象不包含B的成员,可能会导致未定义行为。
- 类似 test1,创建
D对象时先调用C的构造函数,再调用D的构造函数:build C、build D
work()是虚函数,调用的是D的版本:work D
C的析构函数是虚函数,删除时先调用D的析构函数,再调用C的析构函数:delete D、delete C
- 这里创建的是
C对象,所以只调用C的构造函数:build C
- 实际对象是
C,所以work()调用的是C的版本:work C
- 删除时,实际对象是
C,所以只调用C的析构函数:delete C
同样,这种将基类指针强制转换为派生类指针的做法是不安全的。
- 派生类对象创建时,先调用基类构造函数,再调用派生类构造函数
- 虚函数实现多态:基类指针指向派生类对象时,调用的是派生类的虚函数实现
- 基类析构函数应声明为虚函数,以确保删除基类指针时能正确调用派生类析构函数
- 向下转型(基类指针转派生类指针)是不安全的,可能导致未定义行为
这些测试用例很好地展示了 C++ 面向对象编程中的多态性和对象生命周期管理的重要概念。