#include<iostream.h>
class Animal{
public:
Animal(int height,int weight){
//cout<<"animal construct"<<endl;
}
~Animal(){
//cout<<"animal disconstruct"<<endl;
}
void eat(){
cout<<"animal eat"<<endl;
}
void sleep(){
cout<<"animal sleep"<<endl;
}
void breathe(){
cout<<"animal breath"<<endl;
}
};
class Fish: public Animal{
public:
Fish():Animal(400,300),a(1){ //子类中向父类带参数的构造函数传递参数的一种方式
// cout<<"fish construct"<<endl;
}
~Fish(){
// cout<<"fish disconstruct"<<endl;
}
void breathe()
{
//Animal::breathe(); // : 冒号是作用域标识符,主要用于表示是属于哪一个类的.
cout<<"fish bubble"<<endl;
}
private:
const int a; //常量是必须要进行初始化的
};
void fn(Animal *pAn){
pAn->breathe();
}
void main(){
Fish fs;
//fs.breathe();
Animal *pAn;
pAn = &fs;
fn(pAn);
}
程序运行结果如下:

虽说是 Fish fs; 子类创建的对象,但是调用父类的函数,而为调用子类的函数,这就涉及到了类型转换,下面简单说一下类型转换:
| Char ch |
| 1 Byte |

| Int i |
| 1 Byte |
| 1 Byte |
| 1 Byte |
| 1 Byte |
ch = (char)i; 在一个int型转化为char型的时候,4个Byte对1个Byte会丢失精度,这样的转换会出现警告
i = (int)ch; 在一个char型转化为int型的时候,1个Byte可以放到int型的第一个字节当中,这样做是可以的。
ps:如果一个简单的数据类型如char型转换为一个对象,强制类型转换可以骗过编译器,但是运行的时候会报错,这是由于它们之间的内存模型不匹配。
所以当我们产生一个Fish对象的时候,首先它要去构造Animal部分,紧接着构造剩余部 图 Fish对象的内存布局 分,所以当我们把 pAn = &fs; 看似Fish的地址赋给Animal的指针的时候,其实也 是Animal的地址,这样当它调用breathe的方法的时候,调用的就是Animal的 breathe 的方法,所以结果是Animal breathe.
倘若我们想调用Fish的方法,该如何实现呢? 此时需要在Animal的breathe的方法前面加上virtual void breathe() ,当我们加上virtual这个关键字的时候,就是把这个函数定义为虚函数,这种情况是C++中的多态性,它主要是根据你传递的对象的地址来决定所要调用的是哪一个方法。在这个程序中就是,如果子类中重写(覆盖)了基类的函数,在调用的时候父类中的函数用virtual修饰了,就调用子类的,未用virtual修饰就调用父类的方法。
·多态性
当C++编译器在编译的时候,发现Animal类的breathe()函数是虚函数,这个时候C++就会采用延迟绑定(late binding)的技术,在运行时,依据对象的类型(在程序中,我们传递的Fish类对象的地址)来确认调用的哪一个函数,这种能力就是C++的多态性。
本文探讨了C++中关于指针调用函数的问题,特别是涉及多态性的情况。当Fish子类对象通过Animal父类指针调用breathe方法时,由于没有使用virtual关键字,实际调用了Animal的breathe方法。通过添加virtual,可以实现多态性,使得在运行时根据对象的实际类型调用相应的方法,即动态绑定。
3万+

被折叠的 条评论
为什么被折叠?



