C++多态之动态绑定:
1、概念:在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的方法。
使用virtual关键字修饰类的成员函数时,指明该函数为虚函数,派生类需要重新实现,编译器将实现动态绑定。
2、条件:a)必须是虚函数。 b)通过基类类型的引用或者指针调用虚函数。
class Base
{
public:
Base()
{
cout<<"Base:: Base()"<<endl;
}
~Base()
{
cout<<"Base::~Base()"<<endl;
}
virtual void Test1()
{
cout<<"Base:: Test1()"<<endl;
}
int sum(int a, int b)
{
cout<<"Base:: sum =a+b"<<endl;
return a+b;
}
};
class Derived:public Base
{
public:
Derived()
{
cout<<"Derived::Derived()"<<endl;
}
~Derived()
{
cout<<"Derived::~Derived()"<<endl;
}
protected: //基类为public
virtual void Test1()
{
cout<<"Derived:: Test1()"<<endl;
}
virtual int sum(int a, int b)
{
cout<<"Derived:: sum= a+b"<<endl;
return a+b;
}
};
void FunTest1(Base& b) //通过基类的指针或引用访问派生类的成员
{
b.Test1();
}
void FunTest()
{
Derived d;
Base b;
Base& pBase = d;
FunTest1(b);
FunTest1(d);
cout<<"sum = "<<pBase.sum(1,2)<<endl;
}
当修改了派生类中重写的虚函数与原来的返回值不同,编译器报错。
故重写(覆盖)要求具有相同的参数和返回值。而这个规则对于协变则会放松。
3、协变:
在C++中,只要原来的返回类型是基类类型的指针或引用,新的返回值类型是派生类的指针或引用,覆盖的方法就可以改变返回类型,这样的返回类型称为协变返回类型。
class Base
{
public:
Base()
{
cout<<"Base:: Base()"<<endl;
}
~Base()
{
cout<<"Base::~Base()"<<endl;
}
virtual Base& operator=(const Base& b)
{
cout<<"Base::operator=(const Base& b)"<<endl;
return *this;
}
};
class Derived:public Base
{
public:
Derived()
{
cout<<"Derived:: Derived()"<<endl;
}
~Derived()
{
cout<<"Derived::~Derived()"<<endl;
}
virtual Derived& operator=(const Base& b)
{
cout<<"Derived::operator=(const Base& b)"<<endl;
return *this;
}
};
void FunTest()
{
Derived d1,d2;
Base b;
Base& pBase = d1;
pBase.operator=(d2);
}
协变返回类型的优势在于,总是可以在适当程度的抽象层面工作。目前,一般认为,返回值可以协变,参数则不可以。
因此,在C++标准的虚函数中,返回值协变,参数不变。