C++ 继承中方法调用总结
前言
C++ 的继承和多态无疑是一个非常有用的特性,但在实际使用过程中,有一些新手十分容易犯的错误,这里做个整理和总结,列举了继承下各种函数声明及实际调用情况。
类说明
用于演示的类如下:
class Father{
public:
void speak();
};
class Son : public Father{
public:
void speak();
};
测试代码如下:
int main(){
Father f = Father();
f.speak();
Son s = Son();
s.speak();
Father* actual_son = new Son();
actual_son->speak();
return 0;
}
默认覆写
class Father{
public:
void speak(){
cout << "Father speak" << endl;
}
};
class Son : public Father{
public:
void speak(){
cout << "Son speak" << endl;
}
};
// 执行结果:
// Father speak
// Son speak
// Father speak
对于没有任何关键字声明的普通函数,同类型(同名同参数)的子类函数会覆盖父类的函数。这里的覆盖具体是对外隐藏父类的 speak()
,在子类内部仍可以调用父类的 speak()
函数,通过 Father::speak()
调用。
由于不是虚函数,所以就失去了多态的特性,即使实际的对象是子类,调用的仍然是父类的方法。这是因为方法不是虚函数,调用接口是静态绑定的,其调用的方法取决于其指针的类型。
Father* actual_son = new Son();
actual_son->speak();
Son* p = static_cast<Son*>(actual_son);
p->speak();
// 对象本身并没有改变,所使用的指针不同,调用的方法不同
// 输出:
// Father speak
// Son speak
虚函数
class Father{
public:
virtual void speak(){
cout << "Father speak" << endl;
}
};
class Son : public Father{
public:
void speak() override{
cout << "Son speak" << endl;
}
};
// 执行结果:
// Father speak
// Son speak
// Son speak
如果声明为虚函数,就实现了多态,其执行的结果取决于对象本身。
由于虚函数有一个默认实现,所以即使子类没有覆写该虚函数,也不会报错,仍能正常执行。但有时候,我们既想要求子类必须重写该方法,又想提供一个默认实现,此时该如何实现呢?
纯虚函数
class Father{
public:
virtual void speak() = 0;
};
void Father::speak(){
cout << "Father speak" << endl;
}
class Son : public Father{
public:
void speak() override{
cout << "Son speak" << endl;
}
};
class Son2 : public Father{
public:
void speak() override{
Father::speak();
}
};
在这种情况下,Father 中的 speak()
是一个纯虚函数,子类必须重写该方法,但如果只需要默认实现,该纯虚函数还拥有一个默认实现,可以通过显式调用的方式调用。
override 关键字
在本例中,似乎 override
关键字并没有什么作用,即使去掉也没什么影响。但是在继承中,有一些容易犯的错误(但可能难以察觉)通过 override
关键字可以避免。
子类重写父类的方法,有以下条件需要满足:
- 父类方法是虚函数
- 方法返回类型兼容
- 方法名、形参列表、常量属性和引用限定符相同
如果不满足其中一项,则无法完成重写,这个函数会作为一个新的函数定义,而无法实现多态。通过 override
关键字,编译器会自动检查该函数所对应的虚函数,如果找不到则报错。
final 关键字
虽然在本例中没有使用到,但如果想禁止一个方法被子类重写,就可以通过 final
关键字实现。
评论 |
0条评论