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

评论

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

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

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

如果我覆盖了基类的虚函数,可能会重复吗?

总是需要派生类来调用父类函数的反模式是Call super

#1 楼

我冒着明显的危险:调用该函数,如果它在基类中定义,它将自动在派生类中可用(除非是private)。可以通过在基类的名称后加上两个冒号base_class::foo(...)来消除派生类中相同的签名。您应注意,与Java和C#不同,C ++没有用于“基类”的关键字(superbase),因为C ++支持多重继承,这可能会导致歧义。

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

评论


您为什么要两次从同一个类继承?

– Paul Brewczynski
13-10-5在18:39

@bluesm:在经典的OOP中,它没有多大意义,但是在通用编程模板 class C中:public A,public B {};可能由于某种原因而导致两种类型相同,这取决于您的代码使用方式(使A和B相同),可能是不知道您所做的事情的两到三个抽象层方式。

–埃米利奥·加拉瓦利亚(Emilio Garavaglia)
13年11月18日在18:37

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

– Maxim Lavrov
2014-12-26 10:30

@Mathai这就是为什么您不应该使用命名空间std的原因。

– JAB
2015年10月8日在21:06

+1表示您应该注意,与Java和C#不同,C ++没有用于“基类”的关键字。

– TechNyquist
16 Sep 16'8:15

#2 楼

给定一个名为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
16-4-11在13:20



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

– iheanyi
16年4月22日在18:56

@iheanyi听起来很有趣,但对不起,我还没掌握。 foo()是否类似于print()或单独的函数?您是通过使用私有继承来隐藏从基础继承的细节,并为要公开的内容提供公共阴影功能吗?

– underscore_d
16-4-22在19:02



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

– iheanyi
16年4月25日在15:34

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

– iheanyi
16-4-25在15:37



#3 楼

如果您的基类称为Base,而您的函数称为FooBar(),则可以使用Base::FooBar()直接调用它。

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

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


#4 楼

在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)
   }
};



评论


恩,我更喜欢将父代定义为super。

–托马斯·埃丁
2011年11月1日19:06

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

–安德烈
2012年1月30日,下午1:56

我不希望任何人使用它,因为它严重阻碍了代码的可移植性。

– Erbureth说恢复莫妮卡
2014年3月13日在13:42

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

–加百列
2014-12-11 17:39



导致IE6的原因是“开发人员应该知道他们的编译器”,并且包含了非标准功能。

– e2-e4
16年8月4日在10:50



#5 楼

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


Parent :: 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
    }
};


#6 楼

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

#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


评论


感谢您提供一些虚拟实例!

– M.Ionut
4月5日21:06

#7 楼

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();
}


参考示例。

评论


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

–麦凯恩♦
2015年2月23日下午5:30

这个答案是关于嵌套类的,而问题是关于派生类的(即使单词“ parent”和“ child”有点误导),因此根本无法回答这个问题。

–约翰内斯·马托基奇(Johannes Matokic)
2015年8月5日在7:54