C++对象切片和对象切片的阻止(纯虚函数让编译器强迫程序猿修改有对象切片的代码)
2014-12-24 00:14
387 查看
下面, 我们来看一下C++中最简单的多态程序:
好, 我们来看看非指针、引用形式的向上类型转换:
上面的现象就是对象的切片, 实际上, 对象的切片容易让程序产生错误, 也无法实现预定的多态功能。 所以, 要避免对象切片, 那该怎么办呢? 不让Animal创建对象不就行了么, 对, 就是这样, 用纯虚函数来做。 让代码产生编译器错误, 强迫程序猿改正错误, 如下:
#include <iostream> using namespace std; class Animal { private: int weight; public: virtual void eat() { cout << "eat" << endl; } }; class People : public Animal { private: string language; public: void eat() { cout << "chi huo" << endl; } }; void fun(Animal *a) { a->eat(); } int main() { People me; fun(&me); // chi huo return 0; }这是指针形式的向上类型转换, 而我们又知道, 在C++中,引用是通过指针来实现的, 所以, 上面的代码也可以转换为等价的引用形式:
#include <iostream> using namespace std; class Animal { private: int weight; public: virtual void eat() { cout << "eat" << endl; } }; class People : public Animal { private: string language; public: void eat() { cout << "chi huo" << endl; } }; void fun(Animal &a) { a.eat(); } int main() { People me; fun(me); // chi huo return 0; }
好, 我们来看看非指针、引用形式的向上类型转换:
#include <iostream> using namespace std; class Animal { private: int weight; public: virtual void eat() { cout << "eat" << endl; } }; class People : public Animal { private: string language; public: void eat() { cout << "chi huo" << endl; } }; void fun(Animal a) { a.eat(); } int main() { People me; fun(me); // eat return 0; }可以看到, 程序的结果是eat, 而不是chi huo, 这又是为什么呢? 原来, 是对象被切片了, 被切割了。 当发生a=me;赋值操作的时候, 由于a和me的容量并不相同(a小me大), 所以a仅仅能容纳me的一部分, 对于编译器来说, 当发生a=me;后, 在fun内部, me的信息丢失了, 即me被切割了, 编译器的眼中全是Animal类型的a。 所以编译器丝毫感觉不到me的存在, a就是a了, 因此, 上面程序的结果自然就是eat.
上面的现象就是对象的切片, 实际上, 对象的切片容易让程序产生错误, 也无法实现预定的多态功能。 所以, 要避免对象切片, 那该怎么办呢? 不让Animal创建对象不就行了么, 对, 就是这样, 用纯虚函数来做。 让代码产生编译器错误, 强迫程序猿改正错误, 如下:
#include <iostream> using namespace std; class Animal { private: int weight; public: virtual void eat() = 0; }; class People : public Animal { private: string language; public: void eat() { cout << "chi huo" << endl; } }; void fun(Animal a) // error { a.eat(); } int main() { People me; fun(me); return 0; }这样, 就有了编译错误, 从而强迫程序猿修改, 避免非指针、引用形式的向上类型转换 (对象切片)。
相关文章推荐
- 编写可复用性更好的C++代码——Band对象和COMToys(四)
- 编写可复用性更好的C++代码——Band对象和COMToys(五)
- C++对象内存布局--④VS编译器--单个虚拟继承
- C++对象内存布局--⑨VS编译器--虚拟继承--菱形继承
- C++对象内存布局--⑧GCC编译器--虚拟继承多个基类
- 编写可复用性更好的C++代码——Band对象和COMToys(一)
- c++代码在不同编译器之间的移植的小故事 - 循环变量
- C++中有关volatile关键字的作用--阻止编译器将其变量优化缓存到寄存器(和线程相关)(转自百度)
- C++文件I/O 以对象写文件后,读出对象时出现乱码,不知道怎么解决,贴出代码如下.
- 对象创建问题:heapOnly,stackOnly代码(C++代码)
- 编写可复用性更好的C++代码——Band对象和COMToys(六)
- 用C/C++实现代码的动态修改(SMC)
- 用C/C++实现代码的动态修改(SMC)
- 编写可复用性更好的C++代码——Band对象和COMToys(九)
- C++实现机制(二)——编译器实现对象模型的方法
- [关于面向对象]C++写的代码
- 编写可复用性更好的C++代码——Band对象和COMToys(七)
- C++中强迫隐式转换this对象到基类所引发的思考
- C++对象内存布局--⑥GCC编译器-虚拟继承的虚基类表可能有两个
- Windows服务用C++代码实现的一些操作-1:修改服务启动类型