서브 클래스에서 슈퍼 클래스 생성자를 호출하기위한 C ++ 규칙은 무엇입니까?
예를 들어, Java에서는 하위 클래스 생성자의 첫 번째 줄로 사용해야한다는 것을 알고 있습니다. (그렇지 않으면 암묵적으로 수퍼 슈퍼 생성자가 호출됩니다. 누락 된 경우 컴파일 오류가 발생합니다) .
기본 클래스 생성자는 인수가없는 경우 자동으로 호출됩니다. 인수를 사용하여 수퍼 클래스 생성자를 호출하려면 서브 클래스의 생성자 초기화 목록을 사용해야합니다. Java와 달리 C ++은 다중 상속 (더 좋거나 나쁨)을 지원하므로 기본 클래스는 "super ()"가 아닌 이름으로 참조되어야합니다.
class SuperClass
{
public:
SuperClass(int foo)
{
// do something with foo
}
};
class SubClass : public SuperClass
{
public:
SubClass(int foo, int bar)
: SuperClass(foo) // Call the superclass constructor in the subclass' initialization list.
{
// do something with bar
}
};
SubClass anObject(1,2)
, 않는다1
그 다음에 전달된다.SuperClass(foo)
(매개 변수의 인수가 됨foo
)? 나는 문서를 높게, 낮게 검색하고 있지만, SubClass 생성자에 대한 인수를 SuperClass 생성자에 인수로 전달할 수 있다고 명시하지는 않습니다. - LazerSharks: SuperClass(foo)
일부.foo
명시 적으로 수퍼 클래스의 생성자에 전달됩니다. - luke
C ++에서 생성자를 입력하기 전에 모든 수퍼 클래스 및 멤버 변수에 대한 인수가없는 생성자가 호출됩니다. 인수를 전달하려면 "생성자 연결"이라는 별도의 구문이 있으며 다음과 같습니다.
class Sub : public Base
{
Sub(int x, int y)
: Base(x), member(y)
{
}
Type member;
};
이 시점에서 아무 것도 실행하지 않으면 이전에 완료된 기초 / 멤버가 소멸자를 호출하고 예외가 호출자에게 다시 전달됩니다. 연쇄 중에 예외를 잡으려면 함수 try 블록을 사용해야합니다.
class Sub : public Base
{
Sub(int x, int y)
try : Base(x), member(y)
{
// function body goes here
} catch(const ExceptionType &e) {
throw kaboom();
}
Type member;
};
이 양식에서는 try 블록~이다.함수 몸체가 아니라 함수 몸체. 이것은 암시 적 또는 명시 적 멤버 및 기본 클래스 초기화뿐만 아니라 함수 본문 중에 던진 예외를 잡을 수 있습니다. 그러나 함수 catch 블록이 다른 예외를 throw하지 않으면 런타임에서 원래 오류를 다시 발생시킵니다. 초기화 중 예외~ 할 수 없다.무시해라.
C ++에는 생성자의 초기화 목록 개념이 있습니다.이 목록은 기본 클래스의 생성자를 호출 할 수 있고 호출해야 할 곳이며 데이터 멤버를 초기화해야하는 곳입니다. 초기화 목록은 콜론 다음에 그리고 생성자 본문 앞에 생성자 시그니처 다음에옵니다. 클래스 A가 있다고 가정 해 봅시다.
class A : public B
{
public:
A(int a, int b, int c);
private:
int b_, c_;
};
그런 다음 B가 int를 취하는 생성자를 가지고 있다고 가정하면 A의 생성자는 다음과 같이 보일 수 있습니다.
A::A(int a, int b, int c)
: B(a), b_(b), c_(c) // initialization list
{
// do something
}
보시다시피 기본 클래스의 생성자는 초기화 목록에서 호출됩니다. 그런데 초기화 목록의 데이터 멤버를 초기화하는 것은 생성자 본문의 내부에 b_ 및 c_에 대한 값을 할당하는 것보다 바람직합니다. 이는 할당의 추가 비용을 저장하기 때문입니다.
데이터 멤버는 초기화 목록의 순서에 관계없이 클래스 정의에서 선언 된 순서대로 항상 초기화된다는 점에 유의하십시오. 데이터 멤버가 서로 의존하는 경우 발생할 수있는 이상한 버그를 방지하려면 초기화 목록 및 클래스 정의에서 멤버 순서가 항상 동일한 지 확인해야합니다. 같은 이유로 기본 클래스 생성자는 초기화 목록의 첫 번째 항목이어야합니다. 모두 생략하면 기본 클래스의 기본 생성자가 자동으로 호출됩니다. 이 경우 기본 클래스에 기본 생성자가 없으면 컴파일러 오류가 발생합니다.
누구나 초기화 목록을 통해 생성자 호출을 언급했지만 부모 클래스의 생성자가 파생 된 멤버의 생성자 본문에서 명시 적으로 호출 될 수 있다고는 아무도 언급하지 않았습니다. 질문보기하위 클래스에서 기본 클래스의 생성자를 호출합니다. ' 생성자 본문예를 들면. 요점은 파생 클래스의 본문에서 부모 클래스 또는 수퍼 클래스 생성자에 대한 명시 적 호출을 사용하는 경우 실제로는 부모 클래스의 인스턴스를 만드는 것이며 파생 된 객체에서 부모 클래스 생성자를 호출하지 않는다는 것입니다 . 파생 클래스의 객체에서 상위 클래스 또는 상위 클래스 생성자를 호출하는 유일한 방법은 파생 클래스 생성자 본문이 아닌 초기화 목록을 사용하는 것입니다. 아마 "수퍼 클래스 생성자 호출"이라고해서는 안됩니다. 누군가가 혼란 스러울 수 있기 때문에 나는이 대답을 여기에 넣었다.
상위 생성자에 값을 전달하는 유일한 방법은 초기화 목록을 사용하는 것입니다. 초기화 목록은 a :와 그 클래스 생성자에 전달할 값 및 목록을 사용하여 구현됩니다.
Class2::Class2(string id) : Class1(id) {
....
}
또한 부모 클래스에서 매개 변수를 사용하지 않는 생성자가있는 경우 하위 생성자를 실행하기 전에 자동으로 호출됩니다.
인수가없는 생성자가 있으면 파생 클래스 생성자가 실행되기 전에 호출됩니다.
인자를 가진 기본 생성자를 호출하려면 다음과 같이 파생 생성자에 명시 적으로 작성해야합니다.
class base
{
public:
base (int arg)
{
}
};
class derived : public base
{
public:
derived () : base (number)
{
}
};
C ++에서는 부모 생성자를 호출하지 않고 파생 클래스를 생성 할 수 없습니다. 그것은 arg가 아닌 C'tor 인 경우 자동으로 발생합니다. 위에 나온 것처럼 직접 파생 생성자를 호출하거나 코드가 컴파일되지 않으면 발생합니다.
CDerived::CDerived()
: CBase(...), iCount(0) //this is the initialisation list. You can initialise member variables here too. (e.g. iCount := 0)
{
//construct body
}
기본 생성자에 기본 매개 변수가 있으면 기본 클래스가 자동으로 호출됩니다.
using namespace std;
class Base
{
public:
Base(int a=1) : _a(a) {}
protected:
int _a;
};
class Derived : public Base
{
public:
Derived() {}
void printit() { cout << _a << endl; }
};
int main()
{
Derived d;
d.printit();
return 0;
}
출력 : 1
Base()
, 같은 몸을 가진Base(int)
목표 플러스 목표에 대한 암시 적 초기화: _a{1}
. 그것의 'Base()
특정 기본 생성자가 init-list에 연결되어 있지 않으면 항상 호출됩니다. 그리고 다른 곳에서 언급했듯이, C ++ 11의 생성자와 중괄호 또는 동등한 초기화는 위임자가 이미 많은 경우에 코드 - 냄새를 풍기고있을 때 기본 인수를 덜 필요하게 만듭니다. - underscore_d
클래스가 여러 클래스에서 파생 될 때 생성자 호출 시퀀스는 언급되지 않았습니다. 시퀀스는 클래스를 파생시키는 동안 언급 된 것과 같습니다.