James McNellis 的回答“你不能echo()
从”的构造函数调用几乎Foo<T>
是正确的。
您不能从Foo<T>
构造函数中虚拟调用它,因为当构造函数的主体Foo<T>
执行时,对象的类型是Foo<T>
. 还没有派生类部分。和你的代码一样的虚拟调用echo()
,然后转到纯虚函数:砰,死。
但是,您可以提供一个纯虚函数的实现,例如,然后从构造函数中echo()
以非虚拟方式调用它,例如。:-) 除了调用实现。虽然您似乎想调用派生类的实现。Foo::echo()
Foo
Foo
现在关于您的问题:
“我真的很喜欢构造函数中的那个函数。”
好吧,当我写这篇文章时,您的(无效)代码如下所示:
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
构造函数调用echo
它继承自的任何类的实现Foo
。
有很多方法可以做到这一点;它们都是关于将派生类的实现知识带入基类。
一种被称为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++ 类型系统中还有一个漏洞,它允许您通过使用成员指针访问受保护的基类状态而无需强制转换。前者很危险,后者晦涩难懂,可能效率低下。所以,不要。
但希望上述解决方案之一适合您,或者一些合适的适应。
哦,顺便说一句,您的问题似乎是一个实例,称为DBDI,初始化期间的动态绑定。您可以在 C++ FAQ 项目23.6 中找到更一般的处理方法 好的,但是有没有办法模拟这种行为,就好像动态绑定在我的基类构造函数中的 this 对象上起作用一样?. 此外,对于 DBDI 是您希望派生类控制/提供基类构造的一部分的特殊情况,请参阅我的博客文章“如何使用零件工厂避免后期构造”。
干杯&hth.,