가상 상속에서 기본 생성자가 호출되는 이유는 무엇입니까?


79

다음 코드에서 유형의 개체를 인스턴스화 할 때 daughter기본 grandmother()생성자가 호출되는 이유를 이해할 수 없습니다 .

클래스 생성자 grandmother(int)의 사양을 따르기 위해 생성자가 호출되어야 mother하거나 가상 상속 때문에이 코드가 전혀 컴파일되지 않아야한다고 생각했습니다.

여기서 컴파일러 grandmother는 내 뒤에 기본 생성자를 자동으로 호출 하지만 요청한 적이 없습니다.

#include <iostream>

class grandmother {
public:
    grandmother() {
        std::cout << "grandmother (default)" << std::endl;
    }
    grandmother(int attr) {
        std::cout << "grandmother: " << attr << std::endl;
    }
};

class mother: virtual public grandmother {
public:
    mother(int attr) : grandmother(attr) {
        std::cout << "mother: " << attr << std::endl;
    }
};

class daughter: virtual public mother {
public:
    daughter(int attr) : mother(attr) {
        std::cout << "daughter: " << attr << std::endl;
    }
};

int main() {
  daughter x(0);
}

어떤 컴파일러 (및 버전)? 어떤 주장으로 그것을 컴파일 했습니까?
orlp

GCC 4.6.3 20120306 (레드햇 4.6.3-2) 페도라 15. 인수 있습니다 -O0 -g3 -Wall -c -fmessage 길이 = 0
사이먼 Desfarges

: g ++ 4.1.2 같은 문제가 codepad.org/L0jBXfSP
orlp

-Wall -pedantic-errors가있는 Ubuntu 4.7 스냅 샷은이를 재현합니다.
juanchopanza 2012 년

답변:


85

가상 상속을 사용할 때 가상 기본 클래스의 생성자는 가장 많이 파생 된 클래스의 생성자에 의해 직접 호출됩니다. 이 경우 daughter생성자 는 생성자를 직접 호출합니다 grandmother.

grandmother초기화 목록에서 생성자를 명시 적으로 호출하지 않았으므로 기본 생성자가 호출됩니다. 올바른 생성자를 호출하려면 다음과 같이 변경하십시오.

daugther(int attr) : grandmother(attr), mother(attr) { ... }

이 FAQ 항목을 참조하십시오 .


2
정말 말이 되네요, 감사합니다! 계층 구조의 모든 생성자는 해당 자식 클래스가 아닌 마지막 클래스에서 호출됩니다. 그건 생각도 못 했어. C ++ 사양은 까다로운 때로는 될 수 있습니다 ...
오렐리 Ribon

감사합니다 ! 따라서 가상 상속의 경우 가장 좋은 방법은 체인의 모든 생성자를 수동으로 호출하는 것입니다.
사이먼 Desfarges

1
@Xriuk 가상 상속을 사용하여 상속 된 클래스의 생성자를 나타냅니다.
interjay

1
그게 할머니가 두 번 부름을 받는다는 뜻인가요? 어머니 안에있는 할머니에게 전화하면 어떻게 되나요?
Youda008

6
@ Youda008 한 번 호출됩니다. 파생 클래스가 아닌 mother직접 인스턴스화하지 않는 한 에서 호출은 무시됩니다 mother.
interjay
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.