一、前言:
- 用一句解释何为多态
- 虚函数
- 纯虚函数
- 派生类和基类调用的关系和方法
二、正文
2.1 何为多态(我的理解)
一个成员函数直到运行时才确定具体使用的实现类型
2.2 虚函数
简单而言,虚函数就是基类成员函数前标注 virtual 的那部分 virtual viod get();
2.2.1 override 和 final
这两个函数声明需要放在一个函数最后面(比如 void get() const override;)
override 标识符作用
1 编译器会检查函数是否写错
2 提高函数的可读性
final 标识符作用
1 子类将不允许再重写该函数
class A {
private:
virtual void getVal(){
std::cout << "A:123" << std::endl;
}
virtual void getTest() final { //不允许子类重写
std::cout << "A:223" << std::endl;
}
};
class B : private A {
public:
void getVal() override {//即便基类是私有类,子类依旧可以重写
std::cout << "B:321" << std::endl;
}
void getTest() override; //这样无法通过编译
};
2.2.2 基类私有化虚函数
示例如 2.2.1 所示,其作用有二:
1 子类可以正常重定义该虚函数
2 避免外界调用该函数,保证封装的完整性
2.2.3 虚函数带默认参数
结论:存有子类的基类调用虚函数,默认参数取决于基类的默认值(具体看示例)
class A {
public:
virtual void getVal(int a = 10) {
std::cout << "A:" << a << std::endl;
}
};
class B : public A {
void getVal(int a = 123) override {
std::cout << "B:" << a << std::endl;
}
};
int main() {
A* a = new B;
a->getVal();
}
//output
B:10
2.2.4 dynamic_cast 应用场景
基类到子类且(基类至少带有一个虚函数),因为 dynamic_cast 是带有运行检查的,可以确保得到一个非虚的函数,错误返回 nullptr;
其他情况可以使用 static_cast
2.2.5 析构或构造函数调用 虚函数
这个时候由于是静态调用,默认会直接调用该虚函数在父类的实现
2.3 纯虚函数
特征一:virtual void test() = 0; 就是末尾 "=0“
特征二:不能被构建对象
特征三:常用于 C++ 声明接口
class A {
public:
virtual int getVal() = 0;
};
class B : public A {
public:
int getVal() override {
std::cout<<"B:"<<222<<std::endl;
return 100;
}
};
class C : public A {
public:
int getVal() override {
std::cout << "C:"<<333<<std::endl;
return 222;
}
};
int main() {
B b;
C c;
std::vector<A*> aPtr {&b, &c};
for (const auto& temp : aPtr)
temp->getVal();
}
//output
B:222
C:333
2.4 派生类与基类的之间调用
2.4.1 派生类对象的地址可以存在基类指针或引用中,反之不行
由于派生类继承了基类全部成员,因此不会出现基类调用的对象在派生类中不存在
class A {
};
class B : public A {
};
class C : public A {
};
int main() {
A *a1 = new B;
A *a2 = new C;
}