如果我要重写基类的虚函数,可以调用它吗?


340

假设我有课程,Foo并且Bar设置如下:

class Foo
{
public:
    int x;

    virtual void printStuff()
    {
        std::cout << x << std::endl;
    }
};

class Bar : public Foo
{
public:
    int y;

    void printStuff()
    {
        // I would like to call Foo.printStuff() here...
        std::cout << y << std::endl;
    }
};

如代码中所注释,我希望能够调用我要重写的基类的函数。在Java中有super.funcname()语法。这在C ++中可能吗?



1
对于Google员工:请注意,您可能会遇到类似我将其存储为不是指针的类成员变量的问题。在这里查看我的答案:stackoverflow.com/questions/4798966/…我涉及到new / delete修复。
安德鲁

Answers:


448

C ++语法如下:

class Bar : public Foo {
  // ...

  void printStuff() {
    Foo::printStuff(); // calls base class' function
  }
};

11
这样做有任何可能的问题吗?这是不好的做法吗?
Robben_Ford_Fan_boy 2011年

36
@David:不,这样做是很正常的,但是如果它真的有用的话,这可能取决于您的实际班级。仅在需要执行某些操作时才调用基类方法;)。
某事

20
注意,当您的客户需要这样做时,这是一种代码气味!(称为call super requirement,请在此处查看:en.wikipedia.org/wiki/Call_super
v.oddou

8
@ v.oddou:在有用的情况下调用超类没有什么错。您链接的页面只是有关继承的一些特定潜在问题。它甚至说自己有什么错调用父类一般:“请注意,这是需要调用父认为是反模式的有实际代码中的许多例子,其中子类中的方法仍可能。想要超类的功能,通常只在其中增加父功能。”
2014年

26
这对于大多数人来说可能是显而易见的,但是为了完整起见,请记住不要在构造函数和析构函数中这样做。
TigerCoding 2014年

123

是,

class Bar : public Foo
{
    ...

    void printStuff()
    {
        Foo::printStuff();
    }
};

它与superJava中的相同,不同之处在于它允许您在具有多个继承时从不同的基础调用实现。

class Foo {
public:
    virtual void foo() {
        ...
    }
};

class Baz {
public:
    virtual void foo() {
        ...
    }
};

class Bar : public Foo, public Baz {
public:
    virtual void foo() {
        // Choose one, or even call both if you need to.
        Foo::foo();
        Baz::foo();
    }
};

7
这是比所选答案更好的答案。谢谢。
疯狂物理学家2014年

多重继承?噢!
lamino

69

有时,当您不在派生函数中时,您需要调用基类的实现...它仍然有效:

struct Base
{
    virtual int Foo()
    {
        return -1;
    }
};

struct Derived : public Base
{
    virtual int Foo()
    {
        return -2;
    }
};

int main(int argc, char* argv[])
{
    Base *x = new Derived;

    ASSERT(-2 == x->Foo());

    //syntax is trippy but it works
    ASSERT(-1 == x->Base::Foo());

    return 0;
}

2
请注意,您既需要x输入类型,Base*又需要使用Base::Foo语法才能正常工作
TTimo,

27

万一您为类中的许多功能执行此操作,以防万一:

class Foo {
public:
  virtual void f1() {
    // ...
  }
  virtual void f2() {
    // ...
  }
  //...
};

class Bar : public Foo {
private:
  typedef Foo super;
public:
  void f1() {
    super::f1();
  }
};

如果要重命名Foo,可以节省一些编写工作。


1
做到这一点很有趣,但不能与多重继承一起使用。
疯狂物理学家2014年

5
如果您有超过1个基类怎么办?无论如何,试图弯曲C ++使其看起来像其他语言是愚蠢的,而且通常是徒劳的。只要记住基地的名字,然后用它来称呼它即可。
underscore_d

6

如果要从其派生类中调用基类的函数,则可以简单地在覆盖的函数中调用并提及基类名称(例如Foo :: printStuff())。

代码在这里

#include <iostream>
using namespace std;

class Foo
{
public:
    int x;

    virtual void printStuff()
    {
         cout<<"Base Foo printStuff called"<<endl;
    }
};

class Bar : public Foo
{
public:
    int y;

    void printStuff()
    {
        cout<<"derived Bar printStuff called"<<endl;
        Foo::printStuff();/////also called the base class method
    }
};

int main()
{
    Bar *b=new Bar;
    b->printStuff();
}

同样,您可以在运行时使用该类的对象(派生或基类)确定要调用哪个函数。但这要求您在基类上的函数必须标记为虚函数。

下面的代码

#include <iostream>
using namespace std;

class Foo
{
public:
    int x;

    virtual void printStuff()
    {
         cout<<"Base Foo printStuff called"<<endl;
    }
};

class Bar : public Foo
{
public:
    int y;

    void printStuff()
    {
        cout<<"derived Bar printStuff called"<<endl;
    }
};

int main()
{

    Foo *foo=new Foo;
    foo->printStuff();/////this call the base function
    foo=new Bar;
    foo->printStuff();
}

0

检查这个...

#include <stdio.h>

class Base {
public:
   virtual void gogo(int a) { printf(" Base :: gogo (int) \n"); };    
   virtual void gogo1(int a) { printf(" Base :: gogo1 (int) \n"); };
   void gogo2(int a) { printf(" Base :: gogo2 (int) \n"); };    
   void gogo3(int a) { printf(" Base :: gogo3 (int) \n"); };
};

class Derived : protected Base {
public:
   virtual void gogo(int a) { printf(" Derived :: gogo (int) \n"); };
   void gogo1(int a) { printf(" Derived :: gogo1 (int) \n"); };
   virtual void gogo2(int a) { printf(" Derived :: gogo2 (int) \n"); };
   void gogo3(int a) { printf(" Derived :: gogo3 (int) \n"); };       
};

int main() {
   std::cout << "Derived" << std::endl;
   auto obj = new Derived ;
   obj->gogo(7);
   obj->gogo1(7);
   obj->gogo2(7);
   obj->gogo3(7);
   std::cout << "Base" << std::endl;
   auto base = (Base*)obj;
   base->gogo(7);
   base->gogo1(7);
   base->gogo2(7);
   base->gogo3(7);

   std::string s;
   std::cout << "press any key to exit" << std::endl;
   std::cin >> s;
   return 0;
}

输出

Derived
 Derived :: gogo (int)
 Derived :: gogo1 (int)
 Derived :: gogo2 (int)
 Derived :: gogo3 (int)
Base
 Derived :: gogo (int)
 Derived :: gogo1 (int)
 Base :: gogo2 (int)
 Base :: gogo3 (int)
press any key to exit

最好的方法是使用base :: function,例如@sth


本问题所述,由于protected继承,这不应该工作。要强制转换基类指针,您必须使用公共继承。
Darkproduct


有趣。阅读完此答案后,我认为在受保护的继承的情况下,派生自Base的事实仅对类本身可见,而对外部也不可见。
Darkproduct

0

是的,您可以调用它。在子类中调用父类函数的C ++语法是

class child: public parent {
  // ...

  void methodName() {
    parent::methodName(); // calls Parent class' function
  }
};

阅读更多有关函数覆盖的信息

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.