ChatGPT解决这个技术问题 Extra ChatGPT

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

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

我不会使用 MSVC __super,因为它是特定于平台的。尽管您的代码可能无法在任何其他平台上运行,但我会使用其他建议,因为它们按照预期的语言进行。
派生类总是需要调用父类函数的反模式是 Call super

J
Jarek C

我将冒险说明这一点:您调用该函数,如果它在基类中定义,则它在派生类中自动可用(除非它是 private)。

如果派生类中存在具有相同签名的函数,您可以通过添加基类名称后跟两个冒号 base_class::foo(...) 来消除歧义。您应该注意,与 Java 和 C# 不同,C++ 没有 为“基类”(superbase)提供关键字,因为 C++ 支持可能导致歧义的 multiple inheritance

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

为什么要从同一个类继承两次?
@bluesm:在经典的 OOP 中它没有多大意义,但在通用编程中 template<class A, class B> class C: public A, public B {}; 可能有两种类型相同,原因取决于您的代码的使用方式(这使得 A 和 B 相同),可能是两个或三个抽象层的方式来自不知道你做了什么的人。
我认为补充一点很有用,即使它不是直接在父类中实现,而是在继承链中的父类之一中实现,它也会调用父类方法。
@Mathai 这就是为什么你不应该使用using namespace std
+1 说明 You should note that unlike Java and C#, C++ does not have a keyword for "the base class"
M
Milan

给定一个名为 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 实际上,即使基本调用没有穿插其他逻辑,它也很有用。假设父类几乎可以完成您想要的一切,但是公开了一个您不希望 child 的用户使用的方法 foo() - 要么是因为 foo() 在 child 中没有意义,要么外部调用 child 会搞砸 child 是什么正在做。所以孩子可能在某些情况下使用 parent::foo() 但提供 foo 的实现,以便他们隐藏父母的 foo() 不被调用。
@iheanyi 听起来很有趣,但抱歉,我还没有掌握它。这里的 foo() 是类似于 print() 还是一个单独的函数?您的意思是使用 private 继承来隐藏从基础继承的细节,并为您确实想要公开的事物提供 public 阴影功能吗?
@underscore_d 是的,foo() 类似于 print()。让我回到使用 print(),因为我认为在这种情况下它会更有意义。假设某人创建了一个类,该类对特定数据类型执行一组操作,公开了一些访问器,并有一个 print(obj&) 方法。我需要一个在 array-of-obj 上工作的新课程,但其他一切都是一样的。组合会导致大量重复的代码。继承将在 print(array-of-obj&) 循环中调用 print(obj&) 的情况最小化,但不希望客户端调用 print(obj&),因为他们这样做没有意义
@underscore_d 这是基于我无法重构原始父类的公共部分或者这样做非常昂贵的假设。私有继承可以工作,但是您会失去您所依赖的公共访问器 - 因此需要复制代码。
T
TankorSmash

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

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

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

A
Andrey

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


嗯,我更喜欢 typdefsuper 这样的父级。
我不会试图证明 __super 的使用是合理的;我在这里提到它作为替代建议。开发人员应该了解他们的编译器并了解其功能的优缺点。
我宁愿不鼓励任何人使用它,因为它严重阻碍了代码的可移植性。
我不同意 Andrey 的观点:如果我们考虑编写主要独立于编译器的软件,开发人员应该了解标准并且不需要为编译器功能而烦恼,我认为无论如何这是一个好主意,因为迟早在大型项目中会有多个编译器反正都是用的。
“开发人员应该了解他们的编译器”这种推理,以及包含非标准功能,是导致 IE6 的原因......
D
Dean P

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

父::方法()

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

A
Ajay yadav

如果基类成员函数的访问修饰符是protected OR public,则可以从派生类调用基类的成员函数。可以从派生的成员函数调用基类的非虚拟和虚拟成员函数。请参考程序。

#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

感谢您提供 virtual 的一些示例!
s
superbem
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();
}

参考例子。


您能否edit解释一下这段代码为什么/如何回答这个问题?不鼓励仅使用代码的答案,因为它们不像带有解释的代码那样容易学习。如果没有解释,就需要花费更多的时间和精力来了解正在做什么、对代码所做的更改,或者代码是否有用。对于试图从答案中学习的人和评估答案以查看答案是否有效或是否值得投票的人来说,解释都很重要。
这个答案是关于嵌套类的,而问题是关于派生类的(尽管“父”和“子”这两个词有点误导),因此根本没有回答这个问题。