Program Club

생성자의 C ++ 가상 함수

proclub 2020. 12. 15. 19:30
반응형

생성자의 C ++ 가상 함수


이 질문에 이미 답변이 있습니다.

다음 예제에서 "0"을 인쇄하는 이유는 무엇이며 예상대로 "1"을 인쇄하려면 무엇을 변경해야합니까?

#include <iostream>
struct base {
   virtual const int value() const {
      return 0;
   }
   base() {
      std::cout << value() << std::endl;
   }
   virtual ~base() {}
};

struct derived : public base {
   virtual const int value() const {
      return 1;
   }
};

int main(void) {
   derived example;
}

왜냐하면는 base먼저 건설되고 derived아직 "성숙" 하지 않았기 때문입니다. 개체가 이미 제대로 초기화되었는지 보장 할 수없는 경우 개체에 대한 메서드를 호출 할 수 없습니다.


파생 개체가 생성 될 때 파생 클래스 생성자의 본문이 호출되기 전에 기본 클래스 생성자가 완료되어야합니다. 파생 클래스 생성자가 호출되기 전에 생성중인 개체의 동적 유형은 파생 클래스 인스턴스가 아닌 기본 클래스 인스턴스입니다. 이러한 이유로 생성자에서 가상 함수를 호출 할 때 기본 클래스 가상 함수 재정의 만 호출 할 수 있습니다.


실제로이 동작을 얻을 수있는 방법이 있습니다. "소프트웨어의 모든 문제는 간접적 인 수준으로 해결할 수 있습니다."

/* Disclaimer: I haven't done C++ in many months now, there might be a few syntax errors here and there. */
class parent
{
public:
     parent( ) { /* nothing interesting here. */ };
protected:
     struct parent_virtual
     {
         virtual void do_something( ) { cout << "in parent."; }
     };

     parent( const parent_virtual& obj )
     {
          obj.do_something( );
     }
};

class child : public parent
{
protected:
     struct child_virtual : public parent_virtual
     {
         void do_something( ) { cout << "in child."; }
     };
public:
      child( ) : parent( child_virtual( ) ) { }
};

생성자에서 가상 메서드를 다형 적으로 호출 해서는 안됩니다 . 대신 객체 생성 후 호출 할 수 있습니다.

코드는 다음과 같이 다시 작성할 수 있습니다.

struct base {
   virtual const int value() const {
      return 0;
   }
   base() {
      /* std::cout << value() << std::endl; */
   }
   virtual ~base() {}
};

struct derived : public base {
   virtual const int value() const {
      return 1;
   }
};

int main(void) {
   derived example;
   std::cout << example.value() << std::endl;
}

작동 방식 에 대한 질문은 FAQ 항목 입니다.

요약하면, 클래스 T가 생성되는 동안 동적 유형은이며 T, 이는 파생 된 클래스 함수 구현에 대한 가상 호출을 방지합니다. 허용되는 경우 관련 클래스 불변이 설정되기 전에 코드를 실행할 수 있습니다 (Java 및 C #의 일반적인 문제이지만 C ++는 안전합니다. 이 점에서).

기본 클래스 생성자에서 파생 클래스 특정 초기화를 수행하는 방법에 대한 질문은 이전에 언급 한 바로 다음에 나오는 FAQ 항목 이기도 합니다 .

요약하면 정적 또는 동적 다형성을 사용하여 관련 함수 구현을 기본 클래스 생성자 (또는 클래스)까지 전달할 수 있습니다.

One particular way to do that is to pass a “parts factory” object up, where this argument can be defaulted. For example, a general Button class might pass a button creation API function up to its Widget base class constructor, so that that constructor can create the correct API level object.


The general rule is you don't call a virtual function from a constructor.


In C++, you cannot call a virtual / overriden method from a constructor.

Now, there is a good reason you can do this. As a "best practice in software", you should avoid calling additional methods from your constructor, even non virtual, as possible.

But, there is always an exception to the rule, so you may want to use a "pseudo constructor method", to emulate them:

#include <iostream>

class base {
   // <constructor>
   base() {
      // do nothing in purpouse
   }
   // </constructor>

   // <destructor>
   ~base() {
      // do nothing in purpouse
   }
   // </destructor>

   // <fake-constructor>
   public virtual void create() {
      // move code from static constructor to fake constructor
      std::cout << value() << std::endl;
   }
   // </fake-constructor>

   // <fake-destructor>
   public virtual void destroy() {
      // move code from static destructor to fake destructor
      // ...
   }
   // </fake-destructor>

   public virtual const int value() const {
      return 0;
   }

   public virtual void DoSomething() {
      // std:cout << "Hello World";
   }
};

class derived : public base {
   // <fake-constructor>
   public override void create() {
      // move code from static constructor to fake constructor
      std::cout << "Im pretending to be a virtual constructor," << std::endl;
      std::cout << "and can call virtual methods" << std::endl;
   }
   // </fake-constructor>


   // <fake-destructor>
   public override void destroy() {
      // move code from static destructor to fake destructor
      std::cout << "Im pretending to be a virtual destructor," << std::endl;
      std::cout << "and can call virtual methods" << std::endl;
   }
   // </fake-destructor>

   public virtual const int value() const {
      return 1;
   }
};

int main(void) {
   // call fake virtual constructor in same line, after real constructor
   derived* example = new example(); example->create();

   // do several stuff with your objects
   example->doSomething();

   // call fake virtual destructor in same line, before real destructor
   example->destroy(); delete example();
}

As a plus, I recommend programmers to use "struct" for only fields structures, and "class" for structures with fields, methods, constructors, ...

ReferenceURL : https://stackoverflow.com/questions/496440/c-virtual-function-from-constructor

반응형