编程语言
首页 > 编程语言> > C++的多态与切片问题(Section Problem)

C++的多态与切片问题(Section Problem)

作者:互联网

原文链接:http://www.cnblogs.com/yewei/archive/2013/02/28/2937079.html

 

 1 //: Poly.cpp
 2 #include <iostream>
 3 
 4 using namespace std;
 5 
 6 class A {
 7   public:
 8      A() : x(5) {}
 9     virtual void foo() {
10       cout << "x = " << x << endl;
11     }
12   
13     int x;
14 };
15 
16 class B : public A {
17   public:
18     B() : y(10) {}
19     virtual void foo() {
20       cout << "x = " << x << endl;
21       cout << "y = " << y << endl;
22     }
23   
24     int y;
25 };
26 
27 int main() {
28   A a;
29   B b;
30 
31   b.x = 1;
32   b.y = 2;
33   
34   a = b;
35   a.foo();
36   b.foo();
37   
38   return 0;
39 } ///:~

A是基类,B是派生类,其中 a = b 存在向上映射的关系,可以认为向上映射总是安全的,因为是从更专门到更为一般

在编译期完成后,对象 a 和 b 都被分配了一块内存空间,当然,这块内存空间存在于栈空间中

 因此,在编译阶段时,编译器就已经固定好对象 a 和 b 的内存空间大小了。显然,由类 A 继承而来的对象 b 获得类 A 的所有公有成员函数和成员变量,而对于更为专门的对象 b,在执行 a = b 时,因为 b 实际的栈内存空间比 a 大,a 的栈空间便无法再容纳 b 中多出的一块栈空间(这里是存放 y 的空间),而对象 b 的公有成员变量 x 仍然能够传递给 a,正是因为对象 a 中并没有名为 y 的成员变量,因此也没有多余的栈空间去存放由对象 b 传递而来的 y,这正是著名的切片问题(Section Problem)

 

 1 //: Poly.cpp
 2 #include <iostream>
 3 
 4 using namespace std;
 5 
 6 class A {
 7   public:
 8     A() : x(5) {}
 9     virtual void foo() {
10       cout << "x = " << x << endl;
11     }
12   
13     int x;
14 };
15 
16 class B : public A {
17   public:
18     B() : y(10) {}
19     virtual void foo() {
20       cout << "x = " << x << endl;
21       cout << "y = " << y << endl;
22     }
23   
24     int y;
25 };
26 
27 int main() {
28   B *b = new B;
29   b->x = 1;
30   b->y = 2;
31   
32   // A *a = new B;
33   A *a = NULL;
34   a = b;
35   a->foo();
36   b->foo();
37   
38   return 0;
39 } ///:~

对象 b 是一个类指针,当然指针的位置是在栈空间中,但是使用 new 申请的空间却是分配在堆空间中,也就是说,在栈空间中存放了一个类型为 B 的指针,指针的内容是堆空间的地址;对象 a 是一个类指针,同样指针的位置是在栈空间中,但是并没有申请一块堆空间,也就是说,在栈空间存放了一个类型为 A 的空指针。

 

没错,a 是基类 A 的指针,b 是派生类 B 的指针,刚才已经说到过向上映射总是安全的,而这次的 a = b 只是改变 a 指针的指向,此时,a 指针指向了 b 的堆空间,类 A 和 B 中都有 foo 这个函数,并且使用了 virtual 修饰为虚函数(这实现了动态联编的可能性),当执行 a->foo() 的时候,编译器从对象 a 中找到了 vptr 指针,继而在类 A 和 类 B 的 vtbl 中查找相应的虚函数,发现只有类 B 的 foo 能够满足此时 a 指向堆空间的内容(正是 b 所申请的堆空间,含有 x 和 y),因此 a->foo() 和 b->foo() 最终调用的是类 B 的 foo()

 

Java实现多态的方式只有一种,那就是动态联编,也就是通过指针或引用;从另一个角度来说,静态联编带来的问题可能会是切片问题(Section Problem),这是因为栈空间无法进行扩展所导致的;动态联编主要是在运行时通过对象的指针或引用来确定调用的方法(使用 virtual 来修饰函数),因此不适用内联 inline 来修饰,但对于虚函数来说,无论如何都应该避免使用 inline 来修饰,尽管这在静态联编中时可以执行的

转载于:https://www.cnblogs.com/yewei/archive/2013/02/28/2937079.html

标签:函数,联编,Section,绑定,多态,C++,空间,foo,指针
来源: https://blog.csdn.net/weixin_30576827/article/details/98986293