在我的应用程序中,我必须从基类派生一些类,问题是我想强制派生类具有3个特定的构造函数实现。由于c ++没有虚拟纯构造函数,它似乎非常绝望(我必须手动检查每个类的实现,以确保实现特定的ctors,而不是很有趣)。
昨天我发现了一种疯狂的方式来模拟虚拟ctor的组合:
template <class T>
class AbstractEnforcer{
protected:
AbstractEnforcer(){}
private:
static void Enforcer(){
delete new T();
delete new T(*(new unsigned int));
delete new T(*(new unsigned int, *(new QString));
}
}
class AbstractClass : private AbstractEnforcer<AbstractClass>{
}
这种方法唯一的不便是我必须用语法声明所有派生类:
class X : private AbstractEnforcer<X>
即使这不是问题;因为Enforcer()方法永远不会被调用(即使它没有做任何事情[希望如此!!!])
我的问题是: “是否有任何意义(不是宏)强制派生类使用这种机制而不参数化AbstractClass(因为这只能在一个派生级别工作”
template <class T>
class AbstractClass : private AbstractEnforcer<T>{
}
答案 0 :(得分:4)
您的解决方案无法解决问题,因为未使用的模板化代码未实例化,因此除非您手动调用此函数,否则它不会验证是否存在所需的构造函数。
您可以做的是从执行者的构造函数调用此方法:
template <class T>
class AbstractEnforcer{
protected:
AbstractEnforcer(){ Enforcer(); }
private:
static void Enforcer(){
delete new T();
delete new T(*(new unsigned int));
delete new T(*(new unsigned int, *(new QString)));
}
// disable:
AbstractEnforcer (const AbstractEnforcer &enf);
};
class AbstractClass : private AbstractEnforcer<AbstractClass>{
};
int main () {
AbstractClass c;
}
然后,编译器抱怨 - 任务完成。
请注意,我已禁用了复制构造函数,因此无法绕过该检查(通过调用其他构造函数)。
编辑 - 非泄漏Enforcer():[因为绝对不需要在那里使用动态分配..]
static void Enforcer(){
T t1();
T t2(int(3));
T t3(int(4), QString());
}
答案 1 :(得分:3)
请参阅C ++常见问题解答中的this page。
我会做的是这样的事情:
class AbstractClass { public: virtual AbstractClass* create() const = 0; virtual AbstractClass* create(unsigned int) const = 0; virtual AbstractClass* create(unsigned int, QString) const = 0; };
然后,每个派生类都将被强制覆盖这些函数,这些函数应该创建具有不同构造函数的新对象。
答案 2 :(得分:1)
我可能只有一个用于生成测试的模板:
template <typename T>
void enforceConstructors() {
T t1;
T t2(0);
QString q;
T t3(0, q);
}
然后在测试中的某处,执行:
enforceConstructors<X>();
enforceConstructors<Y>();
enforceConstructors<Z>();
对于每个类别X,Y,Z,它们可能在一起,或者在不同的位置。取决于您希望如何组织测试。
如果我使用的值不合适,可以输入一些值,或者编译该测试但不运行它。如果你没有单元测试要么得到一些,或者将以下内容添加到类中(而不是从基类继承):
#ifndef NDEBUG
static void test() { enforceConstructors<X>(); }
#endif
通常不需要将构造函数作为抽象基类定义的接口的一部分。原因是这样的接口用于动态多态 - 您将对象传递给某个函数,并在其上调用函数。你不能将一个类“传递”给一个函数,并让它实例化除了模板之外的类。模板大多数在编译时强制执行它们的接口 - 如果你实例化模板并使用构造函数,那么构造函数必须在那里。
答案 3 :(得分:1)
从这个评论到其中一个答案,我认为你并不是真的希望在这里实现你所要求的,而是另一回事。我所指的评论是:
第1部分:
我知道我们不能有虚拟 构造函数,我不想拥有 一,我的目的是编译器 静态代码检查将发出警报 我,如果我忘了实施具体的 构造函数原型。
第2部分:
我的项目是 插件就像动态加载系统和 我以某种方式强制执行ctors 原型实施第三个 派对代码。
你在问题中提出的是1,你可以用不同的方式强制执行它,只需阅读一些答案,或者看一下元编程示例和boost :: type_traits库。
现在,如果您真正想要的是第2部分:提供动态加载插件机制,那么您不需要强制执行构造函数,而是需要插件对象和插件对象创建的通用接口。无法实例化未知(在编译时)对象的对象的实例,这意味着您将无法从代码中调用构造函数。我建议
// Interface:
class plugin {
public:
virtual void operation() = 0;
};
class plugin_factory {
public:
virtual plugin* create() = 0;
virtual plugin* create( unsigned int ) = 0;
virtual plugin* create( unsigned int, QString const & ) = 0;
};
用户需要提供插件的实现以及创建插件的工厂。他们可能需要为他们的库实现一个入口点,以便您可以访问工厂(或者他们可以在您的系统中注册他们的工厂,否则我建议使用库来实现这些目的(boost :: extension)好像是一个值得关注的地方)
答案 4 :(得分:0)
如果您忘记实现构造函数但在代码中使用它,则会出现编译错误。例如:
Base * p = new Derived( 42 );
如果未提供Derived(int)构造函数,将是编译时错误 - 将不使用Base构造函数。
答案 5 :(得分:0)
我终于采用了这个解决方案,但没有放弃使用:
#ifdef NDEBUG
#ifndef ENFORCE_CTORS
#define ENFORCE_CTORS(enforcingTemplate, enforcedClass) \
friend void enforcingCtors(){static enforcingTemplate<enforcedClass> _enforcer;}
#endif
template<class T>
class AbstractEnforcer : T{
public:
explicit AbstractEnforcer(){
T enforcedCtor0( );
T enforcedCtor1( *(new unsigned int) );
T enforcedCtor2( *(new unsigned int), *(new QString) );
T enforcedCtor3( *(new unsigned int), *(new float ) );
}
};
#endif
并且在每个我不想强制执行的课程中,我只是这样添加:
class X{
ENFORCE_CTORS(AbstractEnforcer, X);
/*
.....
*/
}
我没有找到任何其他方法在类中动态注入此代码。我可能不清楚手术的最终目的(抱歉我可怕的英语)。