多态
多态:不同类型对象调用相同接口完成不同的行为。
根据对象的实际类型不同,可以自动完成不同的行为,而仅仅通过一致的调用形式。
关系
没有封装就不能继承,没有继承就没有运行时的多态。
绑定
早绑定/overload | 晚绑定/override |
---|---|
函数和运算符重载 | 继承与虚函数 |
覆盖(重写override)与虚函数的使用
覆盖成立的三个条件
1.继承
2.子类覆盖(重写)父类虚函数
3.父类指针/引用指向子类多态产生的效果
同样的调用语句实现不同的表现,框架的基石,设计模式的基础。虚函数定义规则:
1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,有无const
.那么即使加上了virtual
关键字,也是不会覆盖。
2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。
3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。
4.内联(inline
)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义,但是在编译的时候系统仍然将它看做是非内联的。
5.构造函数不能是虚函数,因为构造的时候,对象还是一片未定型的空间,只有构造完成后,对象才是具体类的实例。
6.析构函数可以是虚函数,而且通常声明为虚函数。
子类以
new
方式实例化,指针赋值给父类指针,delete
父类指针时,只调用父类的析构函数,不调用子类的析构函数。
class A{
virtual void test(){}
};
class B:public A{
void test(){}
};
class C:public B{
void test(){}
};
class A{
virtual void test(){}
};
class B:public A{
};
class C:public B{
void test(){}
};
特例
class A{
virtual A* test(){}
};
class B:public A{
B* test(){}
};
构造函数和析构函数是否可以是虚函数?
- 多态的实现原理分析
当类中声明虚函数时,编译器会在类中生成一个虚函数表(基类和派生类中各自都会生成一个)
虚函数表
虚函数表是一个存储类成员函数指针的数据结构
虚函数表是由编译器自动生成和维护的
virtual
函数会被编译器放入虚函数表中
存在虚函数时,每个对象当中都有一个指向虚函数表的指针(vptr指针)
- 纯虚函数
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加=0
class 类名{
virtual 返回值类型 函数(形参列表) = 0;
}
- 抽象类
包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。
继承抽象类仍然可能是抽象类?
纯虚函数可以写函数体,但是不可能被调用?
在很多C++书籍上没有覆盖(overrride)这种称谓,而是直接称为多态(polymorphism)。例如:《C++Primer》、《设计模式》、《C++对象模型》、《深入浅出MFC》等。
维基百科polymorphism
Polymorphism can be distinguished by when the implementation is selected: statically (at compile time) or dynamically (at run time, typically via a virtual function).
小结
- 重载覆盖的区别
No. | 重载 | 覆盖 |
---|---|---|
1 | 重载要求函数名相同,但是参数列表必须不同,返回值可以相同也可以不同。 | 覆盖要求函数名、参数列表、返回值必须相同。 |
2 | 在类中重载是同一个类中不同成员函数之间的关系。 | 在类中覆盖则是子类和基类之间不同成员函数之间的关系。 |
3 | 重载函数的调用是根据参数列表决定。 | 覆盖函数的调用是根据对象类型决定。 |
4 | 重载函数是在编译时确定调用一个函数。 | 覆盖函数是在执行时确定调用个函数。 |
- 代码如何判断是否调用了覆盖函数
测验
- 写出下列程序的执行结果,并分析结果。(如果程序编译有错,请分析原因,并写出解决方法)
#include <iostream>
using namespace std;
class A{
public:
virtual void Func(){
cout << "A::Func()" << endl;
}
void Func(int n){
cout << "A::Func( " << n << " )" << endl;
}
};
class B:public A {
public:
using A::Func;
void Func(){
cout << "B::Func()" << endl;
}
};
int main(){
B b;
b.Func();
b.Func(1);
A a(b);
a.Func();
a.Func(2);
A c;
c = b;
c.Func();
c.Func(3);
A* pa = &b;
pa->Func();
pa->Func(4);
A& fa = b;
fa.Func();
fa.Func(5);
return 0;
}
- 参考答案
#include <iostream>
using namespace std;
class A{
public:
virtual void Func(){
cout << "A::Func()" << endl;
}
void Func(int n){
cout << "A::Func( " << n << " )" << endl;
}
};
class B:public A {
public:
// using A::Func;
void Func(){
cout << "B::Func()" << endl;
}
};
int main(){
B b;
b.Func(); // B::Func()
b.Func(1); // 编译错误,同名隐藏
A a(b); // 赋值兼容+默认拷贝构造
a.Func(); // A::Func()
a.Func(2); // 重载 A::Func(2)
A c;
c = b; // 赋值兼容+赋值运算符重载
c.Func(); // A::Func()
c.Func(3); // 重载 A::Func(3)
A* pa = &b; // 赋值兼容
pa->Func(); // 覆盖 B::Func()
pa->Func(4); // 重载 A::Func(4)
A& fa = b; // 赋值兼容
fa.Func(); // 覆盖 B::Func()
fa.Func(5); // 重载 A::Func(5)
return 0;
}
- 写出下列程序的执行结果,并分析结果。(如果程序编译有错,请分析原因,并写出解决方法)
#include <iostream>
using namespace std;
class Base{
public:
Base(){
cout << "Base constuct" << endl;
}
~Base(){
cout << "Base destuct" << endl;
}
};
class Member{
public:
Member(){
cout << "Member constuct" << endl;
}
~Member(){
cout << "Member destuct" << endl;
}
};
class Derive:public Base{
public:
Derive(){
cout << "Derive constuct" << endl;
}
~Derive(){
cout << "Derive destuct" << endl;
}
private:
Member m;
};
int main(){
Base* pD = new Derive;
delete pD;
}
- 写出下列程序的执行结果,并分析结果。(如果程序编译有错,请分析原因,并写出解决方法)
#include <iostream>
using namespace std;
class Base{
public:
virtual void Func()const{ cout << "Base" << endl; }
};
class Derive : public Base {
public:
void Func() const { cout << "Derive" << endl; }
};
int main() {
Base* pB = new Derive;
pB->Func();
(*pB).Func();
}
- 写出下列程序的执行结果,并分析结果。(如果程序编译有错,请分析原因,并写出解决方法)
#include <iostream>
using namespace std;
class A{
public:
void Func(){ cout << "A::Func" << endl;}
};
class B:public A{
public:
virtual void Func(){ cout << "B:Func" << endl;}
};
class C:public B{
public:
virtual void Func(){ cout << "C:Func" << endl;}
};
int main(){
A* a = new C;
a->Func();
}
- 写出下列程序的执行结果,并分析结果。(如果程序编译有错,请分析原因,并写出解决方法)
#include <iostream>
using namespace std;
class Base{
public:
friend ostream& operator<<(ostream& os,const Base& b){ return os << "Base"; }
};
class Derive : public Base {
public:
friend ostream &operator<<(ostream &os, const Derive &b) { return os << "Derive"; }
};
int main() {
Base* pB = new Derive;
cout << (*pB) << endl;
}
双重转发(Double Dispatch)
#include <iostream>
using namespace std;
class Base{
public:
virtual ostream &Put(ostream &os) const { return os << "Base"; }
friend ostream &operator<<(ostream &os,const Base &b) {return b.Put(os);}
};
class Derive : public Base {
public:
ostream &Put(ostream &os) const { return os << "Derive"; }
friend ostream &operator<<(ostream &os, const Derive &b) { return b.Put(os); }
};
int main() {
Base* pB = new Derive;
cout << (*pB) << endl;
}
写出下列执行结果
#include <iostream>
#include <vector>
using namespace std;
class Member{
public:
Member(){cout << __func__ << endl;}
~Member(){cout << __func__ << endl;}
};
class Base{
public:
Base(){cout << __func__ << endl;}
~Base(){cout << __func__ << endl;}
};
class Derive:public Base{
Member m;
public:
Derive(){cout << __func__ << endl;}
~Derive(){cout << __func__ << endl;}
};
int main(){
Base* b = new Derive;
delete b;
}