C++ Primer第五版P535页有这样一段话:在对象之间不存在类型转换。派生类向向基类的自动类型转换只对指针或引用类型有效,在派生类类型和基类类型之间不存在这种转换。
#include<iostream>
#include<stdlib.h>
#include<typeinfo.h>
using namespace std;
class animal
{
public:
void eat()
{
cout<<"animal eat"<<endl;
}
void sleep()
{
cout<<"animal sleep"<<endl;
}
void breath()
{
cout<<"animal breath"<<endl;
}
};
class fish:public animal
{
public:
void breath()
{
cout<<"fish breath"<<endl;
}
};
void fn(animal species)
{
species.breath();
cout<<typeid(species).name()<<endl;
}
void main()
{
fish fh;
//fish* fit;
//fit=&fh;
//fn(fit);
fn(fh);
//cout<<typeid(fit).name()<<endl;
cout<<typeid(fh).name()<<endl;
//cout<<typeid(fh).name()<<endl;
system("pause");
}
在这里,调用fn实参传入时,fish难道不是向animal进行了隐式转换吗?
现在大体知道以上程序通过编译的原因是发生了切掉(sliced down)。
也就是说,当我们用一个派生类对象为一个基类对象初始化赋值时,只有该派生类中的基类部分会被拷贝、移动或赋值,它的派生类部分将被忽略掉。
其实,这和使用指针是相似的。看了半天,我理解的是这样:利用指针进行从派生类到基类的类型转换时,该指针仍是只能指向派生类对象中的基类部分,从狭义功能上来讲,其与类类型转换无差异。
比如
#include<iostream>
#include<stdlib.h>
#include<typeinfo.h>
using namespace std;
class animal
{
public:
void eat()
{
cout<<"animal eat"<<endl;
}
void sleep()
{
cout<<"animal sleep"<<endl;
}
virtual void breathe()
{
cout<<"animal breathe"<<endl;
}
};
class fish:public animal
{
public:
void breathe()
{
cout<<"fish breathe"<<endl;
}
void test()
{
cout<<"test用来判断,将基类的指针或引用绑定到派生类对象时,是否可以利用该指指针或引用调用派生类中的成员"<<endl;
}
};
void fn(animal* species)
{
//species->fish::breathe(); //非法,提示animal中无breathe,尽管我们定义了虚函数
//species->fish::test(); //非法
species->breathe(); //这种调用方式最终调用了fish中的虚函数
species->animal::breathe();
cout<<typeid(species).name()<<endl;
}
void main()
{
fish fh;
animal* fit;
fit=&fh;
fn(fit);
//fn(fh);
cout<<typeid(fit).name()<<endl;
cout<<typeid(fh).name()<<endl;
//cout<<typeid(fh).name()<<endl;
system("pause");
}
那么,使用指针的好处就是可以实现多态了。这才是根本区别。也就是说,若进行了类类型转换,animal就是animal了,编译器是不去记录它原来是什么类型的,也就不存在多态这个说法了。而使用指针时,并在基类中定义虚函数,那么就会触发动态绑定(dynamic binding),运行时就会根据对象的实际类型来调用相应的函数,实现了多态(Polymorphism)