`
姜太公
  • 浏览: 74913 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类
最新评论

C++子类对父类方法的覆盖

阅读更多

昨天看《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在内存里就是同一个东西,使得它们的虚函数表地址一样。

 

分享到:
评论
6 楼 raof01 2008-09-05  
方式1:对象切片
方式2、3:多态。
5 楼 kmh605 2008-08-29  
不知道讲什么
4 楼 iihero 2008-08-29  
<div class='quote_title'>这这跟跟私私有有方法没没有有任任何何关系,,只只跟跟virtual有有关系。。<br/></div>
<div class='quote_title'><br/></div>
<div class='quote_title'><br/></div>
<div class='quote_title'>姜太公 写道</div>
<div class='quote_div'>
<p>昨天看《C++高级编程》,其中讲到了子类可以覆盖父类中的私有方法。当时吓了一跳,如果我用了一个第三方的库,继承了里面的某个类,自己写了个私有方法都得慎之又慎,一不小心可就覆盖了它的私有方法,谁知道会出现什么稀奇古怪的错误!</p>
<p>今天写点代码试了下,发现私有方法是virtual时才能在子类中覆盖。</p>
<pre name='code' class='cpp'>#include &lt;iostream&gt; using namespace std;  class P{ private: virtual void showMeImpl(); public: void showMe(); };  void P::showMeImpl(){ cout &lt;&lt; "here is the parent" &lt;&lt; endl; }  void P::showMe(){ showMeImpl(); }  class C : public P{ private: void showMeImpl(); };  void C::showMeImpl(){ cout &lt;&lt; "here is the child" &lt;&lt; endl; }   int main(int argc, char* argv){ P p; p.showMe(); C c; c.showMe(); }</pre>
<p> 输出:here is the parent<br/>           here is the child<br/> 如果P中的showMeImpl不用virtual修饰,输出就是期望的两次here is the parent。</p>
<p>C++确定什么时候调用哪个方法还是比较上脑筋的。加入子类C重写了父类的showMe方法。输出here is the child。</p>
<pre name='code' class='cpp'>P p; C c; p = c; p.showMe();   //方式1 </pre>
<p> 不管子类和父类方法是否用virtual修饰,都会输出here is parent。</p>
<pre name='code' class='java'>C c; P&amp; p = c; p.showMe();  //方式2 P* p2 = &amp;c; p2-&gt;showMe(); //方式3</pre>
<p> 这两种方式,如果父类和子类的方法用virtual修饰,会调用子类方法。如果没有用virtual修饰,会调用父类方法。</p>
<p> </p>
<p>解释:第二种和第三种方式,如果没有用virtual,同样直接硬编码父类showMe函数地址。用了virtual修饰后,会建立一个虚拟表,包含了指向虚方法实现的指针,调用虚方法时会进入虚拟表以找到正确的实现。所以关于子类覆盖父类私有方法的解释是:调用showMeImpl是进入虚拟表找到子类的实现,所以输出here is child。第一种情况我就不清楚了可能是引用和指针形式下,p和c在内存里就是同一个东西,使得它们的虚函数表地址一样。</p>
<p> </p>
</div>
<p> </p>
3 楼 Joe.Han 2008-08-28  
越看越糊涂了
2 楼 DraculaW 2008-06-26  
很简单的一些概念
不过你讲得好象很复杂...
1 楼 taowen 2008-06-26  
参见inside c++ object model
另外可以对比一下基于模板的静态重载

相关推荐

    c++中子类对象不能调用父类中的虚函数

    然而,这里有一个陷阱:如果通过子类对象直接调用父类的虚函数,编译器会认为是在调用子类自身的实现,即使子类没有覆盖这个虚函数。这就是“子类对象不能调用父类中的虚函数”的含义。例如,假设我们有以下代码: ...

    C++子类父类成员函数的覆盖和隐藏实例详解

    C++子类父类成员函数的覆盖和隐藏实例详解 函数的覆盖  覆盖发生的条件: (1) 基类必须是虚函数(使用virtual 关键字来进行声明) (2)发生覆盖的两个函数分别位于派生类和基类 (3)函数名和参数列表必须完全...

    Java、C++中子类对父类函数覆盖的可访问性缩小的区别介绍

    Java 和 C++ 在子类覆盖父类函数时的可访问性缩小有显著的不同。首先,我们要理解什么是函数覆盖。在面向对象编程中,子类可以重写或覆盖父类的方法,以便实现自己的行为。在 Java 和 C++ 中,这个过程通常是通过...

    C++/JAVA/C#子类调用父类函数情况总结

    - **super.functionName(args)**:在子类中,通过`super`关键字调用父类的非覆盖方法。 **C#** C#与Java类似,但有些微小的差异: 1. **构造函数调用**: - **this(参数)**:类似于Java,C#也允许在子类构造...

    PHP面向对象程序设计子类扩展父类(子类重新载入父类)操作详解

    这种在子类中调用父类被覆盖方法的方式,可以避免复制父类的大量代码,从而实现对原有功能的扩展。例如: ```php class ChildClass extends ParentClass { public function extendedMethod() { parent::method();...

    父类引用指向子类对象

    如果子类和父类在不同包中,子类中`default`访问权限的属性和方法对父类引用来说也是不可见的。 测试代码通常会包含`main`方法,这是程序的入口点。当`main`方法在父类中,或者在与父类同包的其他类中时,可以访问...

    C++类继承之子类调用父类的构造函数的实例详解

    2. **多态性**:通过使用虚函数,子类可以覆盖父类的方法,实现运行时的动态绑定,即多态性。这是C++面向对象编程的重要特性。 3. **继承类型**:C++支持单继承、多继承和菱形继承等多种继承形式。其中,多继承可能...

    关于JAVA继承的讲解

    方法覆盖(Overriding)则发生在子类和父类之间,当子类定义了一个与父类方法同名、同参数列表的方法时,子类的方法会覆盖父类的方法。在覆盖方法时,需要注意以下几点: - 访问权限不能降低,即子类方法不能比父类...

    Java,C#,C++在继承,覆盖和多态,抽象类等几个方面的比较归纳

    覆盖(Override)是指子类重写父类的方法,以实现不同的行为。在Java和C#中,使用`@Override`注解来明确表示方法覆盖,这有助于编译器检查是否正确覆盖了父类方法。而在C++中,无需特殊注解,只需方法签名相同即可...

    C++函数的重载和覆盖

    - **函数覆盖**:在实现面向对象设计时,子类可以根据需要定制或扩展父类的行为,此时需要覆盖父类的虚函数。 了解并熟练掌握C++的函数重载和覆盖,能够使你的代码更具可读性、灵活性和可维护性,也是成为优秀C++...

    C++与操作系统等面试题45

    - **公有继承** (`public`):子类继承父类的所有公共和受保护成员,并且这些成员对子类来说仍然保持其访问级别。 - **保护继承** (`protected`):子类继承父类的所有公共和受保护成员,但这些成员在子类中变为受...

    以员工为编写一个程序,定义如下类:以员工为父类,该类包含员工的基本信息:姓名、年龄、部门。创建两个子类:经理类和工人类,输出经理和工人的工资。在父类中编写getSalary()方法,在子类中覆盖,实现多态。

    1. **增强多态性**:虽然当前的实现已经展示了多态的概念,但可以进一步扩展,例如通过在父类`Employee`中添加更多的通用方法或属性,让子类可以根据需要重写或扩展这些方法。 2. **提高代码质量**:可以通过增加...

    symbian笔试题目啊c++/java

    重写是指子类对父类方法的再次实现,回调函数则是在特定事件发生时调用的函数,常用于异步编程和事件驱动模型。虚函数表是C++实现动态绑定的关键,存储了类的虚函数指针,使得运行时能正确调用子类的虚函数。

    25个C++程序覆盖C++知识重点

    6. **继承与多态**:继承允许一个类(子类)继承另一个类(父类)的属性和行为,实现代码复用。多态则使得不同对象可以响应相同的函数调用,增强了灵活性。 7. **模板**:C++的模板功能允许我们创建泛型代码,适用...

    cpp代码-C++:类02__多继承(子类对象可以转换成父类对象)

    **多继承** 是C++的一个关键特性,它允许一个类(称为派生类或子类)继承一个或多个类(称为基类或父类)的属性和方法。这种继承方式使得子类能够同时具有多个父类的特征,从而增强了其功能和灵活性。例如: ```cpp...

    C++消息机制

    在C++中,子类继承父类的特性,也可以调用父类的方法,这就形成了一个消息传递链。当子类对象调用继承自父类的方法时,可以视为向父类发送消息。例如,一个动物类可以有`makeSound`方法,狗和猫作为动物的子类,分别...

    [C++][Basic] C++父类中实现的纯虚函数体的测试

    这种机制是C++多态性的重要组成部分,使得我们可以创建抽象基类,这些类不能被实例化,但可以作为接口定义,规范子类的行为。本文将深入探讨纯虚函数的使用、意义以及在实际应用中的测试方法。 首先,纯虚函数通过...

    白话C++.,非常好的C++入门级教程

    多态是指同一种操作作用于不同的对象,可以有不同的解释,表现为子类可以覆盖父类的方法。 6. **模板**:模板是C++中实现泛型编程的工具,允许我们编写不依赖特定数据类型的函数或类,提高代码的灵活性和可重用性。...

    Java中子类.pdf

    覆盖则是指子类定义了一个与父类同名、同返回类型和相同参数列表的方法时,子类的方法将替代父类的方法。 隐藏和覆盖是面向对象多态性的体现。它们让子类有能力自定义继承的状态和行为,同时保持与父类的兼容性。...

Global site tag (gtag.js) - Google Analytics