孙鑫视频笔记之——深入理解多态是如何实现的
废话不多说,直接上程序:
1 #include <iostream> 2 using namespace std; 3 4 class Animal 5 { 6 public: 7 Animal() 8 { 9 cout << "我是一个类" << endl; 10 } 11 void eat() 12 { 13 cout << "Animal eat!!!" << endl; 14 } 15 }; 16 17 18 19 class Dog : public Animal 20 { 21 public: 22 void eat() 23 { 24 cout << "狗吃屎!" << endl; 25 } 26 27 }; 28 29 30 int main() 31 { 32 Animal* pAnimal; 33 Dog dog; 34 pAnimal = &dog;//父类的指针指向子类地址,或者说子类地址转化为父类指针 35 pAnimal->eat(); 36 return 0; 37 }
首先Animal他是一个父类。有一个函数叫eat();
Dog是Animal的子类,并且重写了eat(),(这就是所谓的函数的覆盖,ps:不是重点,呵呵)。
现在,我们想看看父类如何调用子类的eat();这是实现多态的根本。
Animal* pAnimal; //声明一个父类的指针
Dog dog; //创建一个子类的对象
pAnimal = &dog; //父类的指针指向子类地址,或者说子类地址转化为父类指针
这里,不知道您会不会产生一个疑惑,“为什么转换的这么的理所当然?”
要知道Animal和Dog 是不同的类,就像int 和 float也不是随随便便可以转的,
搞不好就是精度丢失,您说是不是。那这里将父类的指针储存子类的地址会不会产生什么副作用呢?答案是否定的。这就不得不说说内存模型了!两个类能否相互转化,就得看他们的内存模型是否匹配。我们看看父类和子类的内存模型是怎样的:
我们知道每当创建子类的对象的时候,子类都会调用父类的构造函数,
从而构建父类,(可以理解为,将老爸的基因原原本本的继承下来)。那我们看到
Dog对象的内存分布如上图所示,可以看成老爸的基因在上面,自己的“突变”(基因突变了,哈哈)在下面。
再来看这么一句
pAnimal = &dog; //父类的指针指向子类地址,或者说子类地址转化为父类指针
因为父类和子类的内存模型是一样的,所以这样转换是没有问题的。
pAnimal->eat();那么这么写,父类能调用到子类的eat()吗?
看看Dog的内存模型,就知道了,其实此时pAnimal->eat();依然调用的是父类的eat();
打印出的是:
可惜啊,没有打印出“狗吃屎!”真是可惜了,不急,待哥哥加上一个关键字就万事大吉了!
及在父类的函数eat()前加一个virtual 即可,程序如下:
1 #include <iostream> 2 using namespace std; 3 4 class Animal 5 { 6 public: 7 Animal() 8 { 9 cout << "我是一个类" << endl; 10 } 11 virtual void eat() 12 { 13 cout << "Animal eat!!!" << endl; 14 } 15 }; 16 17 18 19 class Dog : public Animal 20 { 21 public: 22 void eat() 23 { 24 cout << "狗吃屎!" << endl; 25 } 26 27 }; 28 29 30 int main() 31 { 32 Animal* pAnimal; 33 Dog dog; 34 pAnimal = &dog;//父类的指针指向子类地址,或者说子类地址转化为父类指针 35 pAnimal->eat(); 36 return 0; 37 }
哈哈,这回爽了吧,啊哈哈~~
我们看到仅仅加上一个virtual多态的性质就出来了 ,这是因为,加上virtual之后,C++就会
采用迟绑定技术,而不是在一开始编译的时候就确定调用哪个函数,而是在运行的时候去判断
调用哪个函数,如果子类拥有该函数,则使用子类的,如果子类没有实现(重写)这个函数,
那么还是调用父类的。还有一点值得注意,由于父类的eat是虚函数,子类继承了父类,即使
没有加virtual 子类的eat()也是虚函数!
说完虚函数,再讲纯虚函数,这两个我觉得容易混淆,呵呵,一起来分析下:
将父类的eat()稍加改动:virtual void eat() = 0;这个区别是,函数没有实现。
那么这个就是纯虚函数。拥有纯虚函数的类,被称之为抽象类。抽象类无法创建
实例对象。但是可以被继承,继承他的类,要想实例化对象,必须去实现这个
虚函数。如果不实现,那么该子类同样无法实例化对象,因为此时它也是抽象类了。
例子就不再举了,自己去试试吧~~
作者:宋桓公
出处:http://www.cnblogs.com/douzi2/
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。