如何从派生类函数调用父类函数?


602

如何使用C ++从派生类调用父函数?例如,我有一个名为的类parent,一个名为的类child是从父类派生的。每个类中都有一个print函数。在定义孩子的打印功能时,我想调用父母的打印功能。我将如何去做呢?


以上所有解决方案均假定您的打印功能是静态方法。是这样吗 如果该方法不是静态的,则上述解决方案不相关。
hhafez

14
哈夫兹,您误会了base :: function()语法看起来像静态方法调用语法,但是它在这种情况下适用于实例方法。
Motti

2
我不会使用MSVC __super,因为它是特定于平台的。尽管您的代码可能无法在任何其他平台上运行,但我还是会使用其他建议,因为它们是按预期的语言来执行的。
预告片


始终需要派生类调用父类函数的反模式是Call super
Rufus

Answers:


774

我冒着明显的危险:调用该函数,如果该函数在基类中定义,则该函数会自动在派生类中可用(除非它是private)。

如果派生类中有一个具有相同签名的函数,则可以通过在基类名称后加上两个冒号来消除歧义base_class::foo(...)。你应该注意到,不像Java和C#,C ++并没有对“基础类”(关键字superbase),因为C ++支持多重继承,这可能导致歧义。

class left {
public:
    void foo();
};

class right {
public:
    void foo();
};

class bottom : public left, public right {
public:
    void foo()
    {
        //base::foo();// ambiguous
        left::foo();
        right::foo();

        // and when foo() is not called for 'this':
        bottom b;
        b.left::foo();  // calls b.foo() from 'left'
        b.right::foo();  // call b.foo() from 'right'
    }
};

顺便说一句,您不能两次直接从同一个类派生,因为将无法在另一个基础类上引用一个基础类。

class bottom : public left, public left { // Illegal
};

30
您为什么要两次从同一个类继承?
Paul Brewczynski 2013年

65
@bluesm:在经典的OOP中,它没有多大意义,但是在泛型编程template<class A, class B> class C: public A, public B {};中,两种类型可能是相同的,其原因取决于代码的使用方式(使A和B相同),可能是两个或三个不知道您所做的事情的人的抽象层方式。
Emilio Garavaglia

8
我认为添加一下很有用,即使它不是直接在父类实现,而是在继承链中的一个父类中实现,也可以调用父类方法。
Maxim Lavrov 2014年

4
在旁注中,当我尝试将其放入cpp文件时,这使我发疯。我有“使用命名空间标准”。“左”定义在该命名空间中的某处。该示例无法编译-使我发疯:)。然后我将“左”更改为“左”。很好的例子。
Mathai

72
@Mathai这就是为什么您不应该使用的原因using namespace std
2015年

193

给定名为的父类Parent和名为的子类Child,您可以执行以下操作:

class Parent {
public:
    virtual void print(int x);
}

class Child : public Parent {
    void print(int x) override;
}

void Parent::print(int x) {
    // some default behavior
}

void Child::print(int x) {
    // use Parent's print method; implicitly passes 'this' to Parent::print
    Parent::print(x);
}

请注意,这Parent是类的实际名称,而不是关键字。


当然,这仅在基本调用被其他逻辑穿插的情况下才有用,否则覆盖该函数将毫无意义,所以可能有点过分了;)
underscore_d

1
@underscore_d实际上,即使基本调用未插入其他逻辑也很有用。假设父类几乎完成了您想要的所有操作,但是公开了您不希望孩子的用户使用的方法foo()-要么因为foo()在子对象中无意义,要么是外部调用child的孩子会搞砸孩子是什么在做。因此child在某些情况下可以使用parent :: foo(),但提供foo的实现,以使它们隐藏被调用的parent的foo()。
iheanyi

@iheanyi听起来很有趣,但对不起,我还没掌握。是foo()这里类似于print()或一个单独的函数?而你使用的意思是private继承来隐藏细节从基继承,并提供public遮蔽你的东西的功能希望公开?
underscore_d

@underscore_d是,foo()类似于print()。让我回到使用上,print()因为我认为在这种情况下会更有意义。假设有人创建了一个类,该类对特定的数据类型执行了某些操作集,公开了一些访问器并具有一个print(obj&)方法。我需要一个可以使用的新类,array-of-obj但其他所有东西都是相同的。合成导致大量重复的代码。继承在print(array-of-obj&) 循环调用中将其最小化print(obj&),但是不希望客户端进行调用,print(obj&)因为这样做对他们没有意义
iheanyi

@underscore_d这是基于以下假设:我无法重构原始父类的公共部分,或者这样做的成本非常高。私有继承可能会起作用,但随后您将失去依赖的公共访问器,因此需要重复代码。
iheanyi

32

如果调用了基类Base,并且FooBar()调用了函数,则可以直接使用调用它Base::FooBar()

void Base::FooBar()
{
   printf("in Base\n");
}

void ChildOfBase::FooBar()
{
  Base::FooBar();
}

28

在MSVC中,有一个针对此的Microsoft特定关键字:__super


MSDN:允许您明确声明正在为要重写的功能调用基类实现。

// deriv_super.cpp
// compile with: /c
struct B1 {
   void mf(int) {}
};

struct B2 {
   void mf(short) {}

   void mf(char) {}
};

struct D : B1, B2 {
   void mf(short) {
      __super::mf(1);   // Calls B1::mf(int)
      __super::mf('s');   // Calls B2::mf(char)
   }
};


5
恩,我宁愿typdef像这样给父母super
Thomas Eding

26
我不会尝试证明使用__super; 我在这里提到它作为替代建议。开发人员应该了解他们的编译器,并了解其功能的优缺点。
Andrey 2012年

13
我不鼓励任何人使用它,因为它严重阻碍了代码的可移植性。
Erbureth说恢复莫妮卡

26
我不同意Andrey的观点:如果我们考虑编写主要独立于编译器的软件,那么我认为这是一个好主意,因为在大型项目中迟早会有多个编译器,因此开发人员应该了解标准,而不必理会编译器功能。无论如何都使用。
加百利

7
“开发者应该知道自己的编译器”这个推理和非标准功能纳入,是什么导致了IE6 ...
E2-E4

5

如果基类成员函数的访问修饰符是受保护的或公共的,则可以从派生类中调用基类的成员函数。可以从派生成员函数调用基类的非虚拟成员和虚拟成员函数。请参考程序。

#include<iostream>
using namespace std;

class Parent
{
  protected:
    virtual void fun(int i)
    {
      cout<<"Parent::fun functionality write here"<<endl;
    }
    void fun1(int i)
    {
      cout<<"Parent::fun1 functionality write here"<<endl;
    }
    void fun2()
    {

      cout<<"Parent::fun3 functionality write here"<<endl;
    }

};

class Child:public Parent
{
  public:
    virtual void fun(int i)
    {
      cout<<"Child::fun partial functionality write here"<<endl;
      Parent::fun(++i);
      Parent::fun2();
    }
    void fun1(int i)
    {
      cout<<"Child::fun1 partial functionality write here"<<endl;
      Parent::fun1(++i);
    }

};
int main()
{
   Child d1;
   d1.fun(1);
   d1.fun1(2);
   return 0;
}

输出:

$ g++ base_function_call_from_derived.cpp
$ ./a.out 
Child::fun partial functionality write here
Parent::fun functionality write here
Parent::fun3 functionality write here
Child::fun1 partial functionality write here
Parent::fun1 functionality write here

1
感谢您提供一些示例virtual
M.Ioan

5

使用父范围解析运算符调用父方法。

父类:: method()

class Primate {
public:
    void whatAmI(){
        cout << "I am of Primate order";
    }
};

class Human : public Primate{
public:
    void whatAmI(){
        cout << "I am of Human species";
    }
    void whatIsMyOrder(){
        Primate::whatAmI(); // <-- SCOPE RESOLUTION OPERATOR
    }
};

-15
struct a{
 int x;

 struct son{
  a* _parent;
  void test(){
   _parent->x=1; //success
  }
 }_son;

 }_a;

int main(){
 _a._son._parent=&_a;
 _a._son.test();
}

参考示例。


2
您能否编辑此代码为何/如何回答问题的说明?不鼓励仅使用代码的答案,因为它们不像带有解释的代码那样容易学习。如果没有解释,则需要花费大量时间和精力来了解正在执行的操作,对代码所做的更改或代码是否有用。对于试图从答案中学习的人和评估答案以查看答案是否有效或值得投票的人来说,解释都是重要的。
Makyen 2015年

3
这个答案是关于嵌套类的,而问题是关于派生类的(即使单词“ parent”和“ child”有点误导),因此根本无法回答这个问题。
Johannes Matokic
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.