기본 클래스의 가상 함수를 재정의하는 경우이를 호출 할 수 있습니까?


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/… 수정하기 위해 새 / 삭제를 포함했습니다.
앤드류

답변:


449

C ++ 구문은 다음과 같습니다.

class Bar : public Foo {
  // ...

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

11
이를 수행하는 데 가능한 문제가 있습니까? 나쁜 습관입니까?
Robben_Ford_Fan_boy

36
@David : 아니요. 실제로 유용한 경우 실제 클래스에 따라 다를 수 있지만이 작업은 일반적으로 정상입니다. 당신이하고 싶은 일을하는 경우에만 기본 클래스 메소드를 호출하십시오;).
sth

20
주의 이것은이다 코드 냄새 클라이언트가 그것을 할 필수된다! ( call super requirement여기에서 확인하십시오 : en.wikipedia.org/wiki/Call_super )
v.oddou

8
@ v.oddou : 유용 할 때 슈퍼 클래스를 호출하는 데 아무런 문제가 없습니다. 링크 한 페이지는 상속과 관련된 특정 잠재적 문제에 관한 것입니다. 심지어 일반적으로 슈퍼 클래스를 호출에 아무것도 잘못이 있다는 자체를 말한다 : "그것은 참고 것을 요구 안티 패턴 부모를 호출의 실제 코드에서 많은 예제가 어디 서브 클래스의 방법 수도 여전히있다. 수퍼 클래스의 기능을 원한다. 일반적으로 상위 기능 만 보강하는 경우가있다. "
sth

26
대부분의 경우 명백 할 수도 있지만, 완전성을 위해서는 생성자와 소멸자에서 절대로이 작업을 수행하지 않아야합니다.
TigerCoding 2013

123

예,

class Bar : public Foo
{
    ...

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

그것은과 동일 super당신이 다중 상속이있을 때 다른 기지에서 구현을 호출 수를 제외하고, 자바있다.

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
선택한 답변보다 더 나은 답변입니다. 감사.
Mad Physicist

다중 상속? 어이!
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
재미있는 방법이지만 다중 상속으로 작동하지 않습니다.
Mad Physicist

5
기본 수업이 2 개 이상인 경우 어떻게해야합니까? 어쨌든, 다른 언어처럼 보이기 위해 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
  }
};

함수 재정의 에 대해 자세히 알아보십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.