昨天看《C++高级编程》,其中讲到了子类可以覆盖父类中的私有方法。当时吓了一跳,如果我用了一个第三方的库,继承了里面的某个类,自己写了个私有方法都得慎之又慎,一不小心可就覆盖了它的私有方法,谁知道会出现什么稀奇古怪的错误!
今天写点代码试了下,发现私有方法是virtual时才能在子类中覆盖。
#include <iostream>
using namespace std;
class P{
private:
virtual void showMeImpl();
public:
void showMe();
};
void P::showMeImpl(){
cout << "here is the parent" << endl;
}
void P::showMe(){
showMeImpl();
}
class C : public P{
private:
void showMeImpl();
};
void C::showMeImpl(){
cout << "here is the child" << endl;
}
int main(int argc, char* argv){
P p;
p.showMe();
C c;
c.showMe();
}
输出:here is the parent
here is the child
如果P中的showMeImpl不用virtual修饰,输出就是期望的两次here is the parent。
C++确定什么时候调用哪个方法还是比较上脑筋的。加入子类C重写了父类的showMe方法。输出here is the child。
P p;
C c;
p = c;
p.showMe(); //方式1
不管子类和父类方法是否用virtual修饰,都会输出here is parent。
C c;
P& p = c;
p.showMe(); //方式2
P* p2 = &c;
p2->showMe(); //方式3
这两种方式,如果父类和子类的方法用virtual修饰,会调用子类方法。如果没有用virtual修饰,会调用父类方法。
解释:第二种和第三种方式,如果没有用virtual,同样直接硬编码父类showMe函数地址。用了virtual修饰后,会建立一个虚拟表,包含了指向虚方法实现的指针,调用虚方法时会进入虚拟表以找到正确的实现。所以关于子类覆盖父类私有方法的解释是:调用showMeImpl是进入虚拟表找到子类的实现,所以输出here is child。第一种情况我就不清楚了可能是引用和指针形式下,p和c在内存里就是同一个东西,使得它们的虚函数表地址一样。
分享到:
相关推荐
然而,这里有一个陷阱:如果通过子类对象直接调用父类的虚函数,编译器会认为是在调用子类自身的实现,即使子类没有覆盖这个虚函数。这就是“子类对象不能调用父类中的虚函数”的含义。例如,假设我们有以下代码: ...
C++子类父类成员函数的覆盖和隐藏实例详解 函数的覆盖 覆盖发生的条件: (1) 基类必须是虚函数(使用virtual 关键字来进行声明) (2)发生覆盖的两个函数分别位于派生类和基类 (3)函数名和参数列表必须完全...
Java 和 C++ 在子类覆盖父类函数时的可访问性缩小有显著的不同。首先,我们要理解什么是函数覆盖。在面向对象编程中,子类可以重写或覆盖父类的方法,以便实现自己的行为。在 Java 和 C++ 中,这个过程通常是通过...
- **super.functionName(args)**:在子类中,通过`super`关键字调用父类的非覆盖方法。 **C#** C#与Java类似,但有些微小的差异: 1. **构造函数调用**: - **this(参数)**:类似于Java,C#也允许在子类构造...
这种在子类中调用父类被覆盖方法的方式,可以避免复制父类的大量代码,从而实现对原有功能的扩展。例如: ```php class ChildClass extends ParentClass { public function extendedMethod() { parent::method();...
如果子类和父类在不同包中,子类中`default`访问权限的属性和方法对父类引用来说也是不可见的。 测试代码通常会包含`main`方法,这是程序的入口点。当`main`方法在父类中,或者在与父类同包的其他类中时,可以访问...
2. **多态性**:通过使用虚函数,子类可以覆盖父类的方法,实现运行时的动态绑定,即多态性。这是C++面向对象编程的重要特性。 3. **继承类型**:C++支持单继承、多继承和菱形继承等多种继承形式。其中,多继承可能...
方法覆盖(Overriding)则发生在子类和父类之间,当子类定义了一个与父类方法同名、同参数列表的方法时,子类的方法会覆盖父类的方法。在覆盖方法时,需要注意以下几点: - 访问权限不能降低,即子类方法不能比父类...
覆盖(Override)是指子类重写父类的方法,以实现不同的行为。在Java和C#中,使用`@Override`注解来明确表示方法覆盖,这有助于编译器检查是否正确覆盖了父类方法。而在C++中,无需特殊注解,只需方法签名相同即可...
- **函数覆盖**:在实现面向对象设计时,子类可以根据需要定制或扩展父类的行为,此时需要覆盖父类的虚函数。 了解并熟练掌握C++的函数重载和覆盖,能够使你的代码更具可读性、灵活性和可维护性,也是成为优秀C++...
- **公有继承** (`public`):子类继承父类的所有公共和受保护成员,并且这些成员对子类来说仍然保持其访问级别。 - **保护继承** (`protected`):子类继承父类的所有公共和受保护成员,但这些成员在子类中变为受...
1. **增强多态性**:虽然当前的实现已经展示了多态的概念,但可以进一步扩展,例如通过在父类`Employee`中添加更多的通用方法或属性,让子类可以根据需要重写或扩展这些方法。 2. **提高代码质量**:可以通过增加...
重写是指子类对父类方法的再次实现,回调函数则是在特定事件发生时调用的函数,常用于异步编程和事件驱动模型。虚函数表是C++实现动态绑定的关键,存储了类的虚函数指针,使得运行时能正确调用子类的虚函数。
6. **继承与多态**:继承允许一个类(子类)继承另一个类(父类)的属性和行为,实现代码复用。多态则使得不同对象可以响应相同的函数调用,增强了灵活性。 7. **模板**:C++的模板功能允许我们创建泛型代码,适用...
**多继承** 是C++的一个关键特性,它允许一个类(称为派生类或子类)继承一个或多个类(称为基类或父类)的属性和方法。这种继承方式使得子类能够同时具有多个父类的特征,从而增强了其功能和灵活性。例如: ```cpp...
在C++中,子类继承父类的特性,也可以调用父类的方法,这就形成了一个消息传递链。当子类对象调用继承自父类的方法时,可以视为向父类发送消息。例如,一个动物类可以有`makeSound`方法,狗和猫作为动物的子类,分别...
这种机制是C++多态性的重要组成部分,使得我们可以创建抽象基类,这些类不能被实例化,但可以作为接口定义,规范子类的行为。本文将深入探讨纯虚函数的使用、意义以及在实际应用中的测试方法。 首先,纯虚函数通过...
多态是指同一种操作作用于不同的对象,可以有不同的解释,表现为子类可以覆盖父类的方法。 6. **模板**:模板是C++中实现泛型编程的工具,允许我们编写不依赖特定数据类型的函数或类,提高代码的灵活性和可重用性。...
覆盖则是指子类定义了一个与父类同名、同返回类型和相同参数列表的方法时,子类的方法将替代父类的方法。 隐藏和覆盖是面向对象多态性的体现。它们让子类有能力自定义继承的状态和行为,同时保持与父类的兼容性。...