C++的多态与切片问题(Section Problem)
来源:互联网 发布:淘宝卖家可以删差评吗 编辑:程序博客网 时间:2024/06/06 12:57
C++内存分配的方式大体上可以归纳为3种
- 1) 从静态存储区中分配:内存在编译时就已经分配好,这块内存在程序的整个运行期间都存在,例如全局变量,static变量
- 2) 在栈上分配:执行函数时,函数内局部变量的存储单元都可在栈上创建,函数执行结束时,这些存储单元自动被释放
- 3) 在堆上分配:也称为动态内存分配,程序在运行的时候用malloc或new申请任意多少的内存,除非程序运行结束或者程序员自己用free或delete释放动态内存,否则这块动态内存一直存在
多态性是指为一个函数名关联多种含义的能力,即同一种调用方式可以映像到不同的函数。这种把函数的调用与适当的函数体对应的活动又称为绑定(binding)。根据绑定所进行阶段的不同,可分为早期绑定(early binding)、晚期绑定(late binding),早期绑定发生在程序的编译阶段,称为静态联编(static binding),晚期绑定发生在程序的运行阶段,称为动态联编(dynamic binding)。
1) 早期绑定(Early Binding):也称为编译期多态,指绑定是发生在编译阶段。
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)
2)晚期绑定(Late binding):也称为动态联编,指在运行时实现多态
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()
3)静态联编和动态联编
Java实现多态的方式只有一种,那就是动态联编,也就是通过指针或引用;从另一个角度来说,静态联编带来的问题可能会是切片问题(Section Problem),这是因为栈空间无法进行扩展所导致的;动态联编主要是在运行时通过对象的指针或引用来确定调用的方法(使用 virtual 来修饰函数),因此不适用内联 inline 来修饰,但对于虚函数来说,无论如何都应该避免使用 inline 来修饰,尽管这在静态联编中时可以执行的
- C++的多态与切片问题(Section Problem)
- python切片的问题
- python -- 序列索引与切片的一些问题
- 继承中的向上映射与切片问题
- go的学习记录(二)--- 数组与数组切片
- 进程同步02--临界区问题(Critical Section Problem)
- article与section的区别
- tableView设置多个section 的 headerView 粘合性问题
- Problem 2261 浪里个浪(多起点与多终点问题)
- 由vector造成的对象切片问题
- 一种缓存切片更新问题的解决方法
- GeoWebCache发布arcgis10.1的切片问题
- 关于对象切片与多态性的认识
- Python序列的切片操作与技巧
- Python 序列的切片操作与技巧
- python的切片与迭代
- Golang中 的数组与切片
- Python序列的切片操作与技巧
- __stdcall 和 __cdecl 的区别
- tortoiseSVN在使用中因为网络断线或者手动在更新中取消而锁定目录的处理办法
- Android.mk 杂乱分析
- MySQL存储引擎的比较
- 以前写的QTP的脚本(excel相关)
- C++的多态与切片问题(Section Problem)
- 用SQL语句添加删除修改字段
- 亚马逊学习二:产品与服务
- Python string的一些用法
- WebLogic的缓存文件所在位置
- jpa 继承策略
- seo_meta
- mongodb 集合查询$in
- 内存对齐机制