受this question的启发,我想知道是否有任何技巧(如SFINAE)可以实现相反的目标。
编辑:添加示例
我有类似的东西(它非常简化,因为它有很多细节):
#include <iostream>
class Base {
public:
Base(){}
virtual ~Base(){
}
void initialize() { implementation(); }
private:
virtual void implementation() = 0;
};
class Derived : public Base {
private:
virtual void implementation() { std::cout << "initialization" << std::endl;}
};
int main() {
std::unique_ptr<Base> b(new Derived());
b->initialize();
return 0;
}
必须调用初始化方法。
但是如果我将initialize方法放在Base构造函数中,它将调用一个纯虚方法。 我想知道是否有办法阻止某人不正确地使用构造的对象。
编辑:我的“解决方案”:
#include <iostream>
class Base {
public:
virtual ~Base(){
}
Base() {};
private:
void initialize() { implementation(); }
virtual void implementation() = 0;
template<class DerivedType> friend Base *factory();
};
class Derived : public Base {
private:
Derived() {}
virtual void implementation() { std::cout << "initialization" << std::endl;}
template<class DerivedType> friend Base *factory();
};
template<class DerivedType>
static Base *factory(){
Base *b = new DerivedType();
b->initialize();
return b;
}
int main() {
std::unique_ptr<Base> b(factory<Derived>());
return 0;
}
答案 0 :(得分:2)
您不能强制编译错误,但还有其他选择。
如果你的类型的实例只是无效,除非调用了initialize,并且如果记录了这个事实或者在使用时抛出异常(如果未初始化)是不可接受的,那么你应该将构造函数设为私有并公开一个静态方法来创建你的实例类型。
这样,代码的客户端就无法使用您的类型的未初始化实例。如果有一种更好,更优雅的方法,我不知道它(但也许这里有人这样做。)
答案 1 :(得分:1)
请注意,这不应该是必需的,因为在创建对象时,该对象可以正确初始化,而无需调用初始化函数。
这可能听起来很奇怪,但在大多数情况下,initialization()
功能不正确:
class A
{
public:
A() { do initialization of A fields here; }
};
class B : public A
{
public:
B() { do initialization of B fields here; }
};
在大多数情况下,这应该足够了。
如果将参数传递给构造函数,则可能需要一些接口(不在#include中创建循环),然后您只需传递这些参数,如下所示:
class C;
class D;
class A
{
public:
A(C c) { do initialization of A fields here; }
};
class B : public A
{
public:
B(C c, D d) : A(c) { do initialization of B fields here; }
};
否则,要在运行时验证,boost和我的controlled_vars(模板使类型如int safe,最后!)提供了检查字段是否已初始化并且可以抛出的工具并返回默认值。
我不知道编译器中有任何设施可以进行这样的测试。但是,如果你写了一个测试(你应该总是进行测试!)那么你的测试可以做这样的验证。
请注意,我首先想到的是一个分析器,但这需要一个测试,无论如何都要告诉你是否正确,并且分析器可以告诉你初始化被调用,但你不会知道是否发生在所有情况下。
然而,要真正在编译时强制执行此类初始化(假设您确实需要它),如Ed S.所述,最好的可能是使用工厂。这样,所有丑陋的初始化代码都保持隐藏状态。