Foo<T>
생성자의 본문이 Foo<T>
유형의 개체이기 때문에 실제로는 Foo<T>
생성자에서 호출 할 수 없습니다. 파생 된 클래스 부분은 아직 없습니다. 그리고 코드에서와 마찬가지로 echo()
의 가상 호출은 순수한 가상 함수 인 bang, dead로 이동합니다.
그러나 은echo()
같은 순수 가상 함수의 구현을 제공 할 수 있습니다, 다음 Foo
생성자에서, Foo::echo()
같은 비 실질적으로 호출. :-) 그 것을 제외하면 Foo
구현을 호출합니다. 파생 클래스의 구현을 호출하고 싶습니다.
"I'd really like that function in the constructor."
글쎄, 나는이 당신의 (잘못된) 코드를 쓰고 있어요으로하는 것은 다음과 같습니다 : 이제 당신의 문제에 대한
template <typename T> class Foo
{
public:
Foo(T a)
{
x = a;
echo();
}
protected:
T x;
virtual void echo() = 0;
};
class Bar : public Foo<int>
{
public:
Bar(int a) : Foo<int>(a)
{
}
void echo();
};
void Bar::echo()
{
cout << "value: " << x << endl;
}
int main(int argc, char* argv[])
{
Bar bar(100);
return 0;
}
그리고 지금까지 내가 당신의 문제 설명을 이해, Foo
생성자가 Foo
에서 상속하는 모든 클래스의 echo
구현을 호출하게합니다.
이렇게하는 방법에는 여러 가지가 있습니다. 그들은 모두 파생 클래스의 구현에 대한 지식을 기본 클래스에 가져 오는 것에 관한 것입니다.
하나가이 같이 갈 수 CRTP의 호기심 반복 템플릿 패턴로 알려져 있으며, 특정 문제에 적응 :
#include <iostream>
template< class XType, class Derived >
class Foo
{
public:
Foo(XType const& a)
: state_(a)
{
Derived::echo(state_);
}
protected:
struct State
{
XType x_;
State(XType const& x): x_(x) {}
};
private:
State state_;
};
class Bar
: public Foo< int, Bar >
{
private:
typedef Foo< int, Bar > Base;
public:
Bar(int a): Base(a) {}
static void echo(Base::State const&);
};
void Bar::echo(Base::State const& fooState)
{
using namespace std;
cout << "value: " << fooState.x_ << endl;
}
int main()
{
Bar bar(100);
}
을 위 나쁘지 않다 솔루션이며, 그러나 좋지도 않습니다. 실제 문제가 기본 클래스 생성자에서 파생 클래스 비 정적 멤버 함수를 호출하는 경우 유일한 "좋은"대답은 Java 또는 C#이므로 이러한 작업을 수행 할 수 있습니다. 의도적으로 C++에서 지원되지 않습니다. 파생 클래스 객체에서 아직 초기화되지 않은 항목에 실수로 액세스하려고 시도하기가 쉽기 때문입니다.
어쨌든 거의 항상 그렇듯이 컴파일 타임 솔루션이있는 곳에서는 런타임 솔루션이 있습니다.
당신은 단순히 기능을 전달할 수 은과 같이, 생성자의 인수로 실행되는 : 당신이 실행에 비해 컴파일 시간 이외에 (당신은 아마 미묘한 차이를 알게 될 것이다이 두 프로그램을 연구하면
#include <iostream>
template< class XType >
class Foo
{
protected:
struct State
{
XType x_;
State(XType const& x): x_(x) {}
};
public:
Foo(XType const& a, void (*echo)(State const&))
: state_(a)
{
echo(state_);
}
private:
State state_;
};
class Bar
: public Foo<int>
{
private:
typedef Foo<int> Base;
public:
Bar(int a): Base(a, echo) {}
static void echo(Base::State const&);
};
void Bar::echo(Base::State const& fooState)
{
using namespace std;
cout << "value: " << fooState.x_ << endl;
}
int main()
{
Bar bar(100);
}
시간 지식 이전).
마지막으로 더티 캐스트가 포함 된 솔루션이 있으며 멤버 포인터를 사용하여 캐스팅하지 않고 보호 된 기본 클래스 상태에 액세스 할 수있는 C++ 유형 시스템의 허점이 있습니다. 전자는 위험하며 후자는 불분명하고 비효율적 일 수 있습니다. 그러지 마.
하지만 위의 해결 방법 중 하나가 적합하거나 적합한 적응 방법 일 것입니다.
는 누가 -1'd하지만, 귀하의 의견은 바로 나에게 읽습니다. G ++은'warning : abstract virtual 'void Foo :: echo() [with T = int]'가 생성자'에서 호출 된 다음 오류를 발생시킵니다 :'test.cpp :(. text._ZN3FooIiEC2Ei [ Foo :: Foo (int)] + 0x2c) : Foo :: echo() '에 대한 정의되지 않은 참조 –
Ashe
비논리적 인 음색은 필요하지 않지만이 대답은 정확하므로 upvoting을합니다. 바꿔 말하면 가치가 있을지도 모릅니다. 기본적으로 Bar의 생성자가 객체 생성시 Foo의 생성자를 호출하면 Foo는 Bar에 대해 아무 것도 모릅니다. RTTI가 적절한 가상 기능을 시작하고 호출 할 수있는 객체가 완전히 만들어지기 전까지는 아닙니다. – rcv