多态分编译时多态和运行时多态:
编译时多态就是指函数重载,运算符重载,泛型编程。这个很好理解
运行多态是指使用虚函数来实现使用基类的对象的引用或指针来访问派生类成员,即使调用派生类中由基类申明的虚函数。这个也好理解,但是要和非虚函数覆盖区别开来
class Base { private: int a; public: Base(int i=100):a(i){} void get() const { cout<<"NO"<<endl; } }; class Her:public Base{ public: void get()const { cout<<"YEs"<<endl; } }; void mycall(Base &b) { b.get(); } int main() { Base A; Her B; mycall(A); mycall(B); system("pause"); }mycall(A),mycall(B)结果都调用了基类的get函数。 基类类型的指针或引用可以引用基类类型的对象,也可以引用派生类类型的对象。
无论实际对象时哪种类型,编译器都当做是基类类型的对象,因为将派生类对象当做基类对象是安全的。
结论:不管传给mycall的实际实参类型是什么,在编译的时候就确定了调用基类 的get函数。
使用虚函数
class Base { private: int a; public: Base(int i=100):a(i){} virtual void get() const { cout<<"NO"<<endl; } }; class Her:public Base{ public: void get()const { cout<<"YEs"<<endl; } }; void mycall(Base &b) { b.get(); } int main() { Base A; Her B; mycall(A); mycall(B); system("pause"); }
虚函数的好处就是,用户不用关心你当前针对的是基类还是派生类。
结论:根据传入实参实际类型不同,在运行时动态绑定各自的get函数。
class Base {
private:
int a;
public:
Base(int i=100):a(i){}
virtual void get() const {
cout<<"NO"<<endl;
}
};
class Her:public Base{
public:
void get()const {
cout<<"YEs"<<endl;
}
};
void mycall(Her &b) {
b.get();
}
int main() {
Base A;
Her B;
mycall(A);//出错,与mycall的形参类型不符
mycall(B);
system("pause");
}
上面这个列子意思就是,基类包含于派生类中,可以通过基类对象的引用或指针来代替派生类,当然只能访问基类中含有的成员。
也可以使用覆盖虚函数机制,使用作用域操作符覆盖函数:比如要调用派生类Her的get函数,可以使用 Her::get();
结论:使用非虚函数:函数形参为基类对象的引用(或指针),在调用该函数的时候,无论实际对象是基类还是派生类对象,都执行基类类型定义的函数。
使用虚函数:函数形参为基类对象的引用(或指针),在调用该函数的时候,由实际的对象类型动态绑定不同的虚函数。
注意:基类对象的引用和基类对象作为形参的区别
1.基类对象作为形参:即使是定义的虚函数,传入派生类对象,也会调用该基类的虚函数,而不是派生类的虚函数。因为以基类对象作为形参,会将传入的派生类对象的基类部分复制到形参。
class Base { private: int a; public: Base(int i=100):a(i){} virtual void get() const { cout<<"NO"<<endl; } }; class Her:public Base{ public: void get()const { cout<<"YEs"<<endl; } void get1() { cout<<"get1"<<endl; } }; void mycall(Base b) { b.get(); /* 将派生类对象传给希望接收基类类型对象的形参,派生类对象的基类部分被复制到形参 */ } void mycall(Base &b) { b.get(); /* 将派生类对象传给接收基类类型引用的形参,引用直接绑定该该对象,对象本身没有复制, 这个不会改变对象是派生类的现状mycall(B);结果B还是派生类对象。 */ } int main() { Base A; Her B; mycall(A); mycall(B); system("pause"); }