2

这个问题的启发,我想知道是否有任何技巧(如 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;
}

必须调用初始化方法。

但是如果我将初始化方法放在 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;
}
4

2 回答 2

2

您不能强制编译器错误,但还有其他选择。

如果您的类型的实例根本无效,除非调用 initialize,并且如果记录该事实或在使用时抛出异常(如果未初始化)是不可接受的,那么您应该将构造函数设为私有并公开一个静态方法来创建您的类型的实例。

这样,您的代码客户端根本无法使用您类型的未初始化实例。如果有更好、更优雅的方法,我不知道(但也许这里有人知道)。

于 2012-06-28T21:42:28.183 回答
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和我的受控变量(使 int 等类型安全的模板,终于!)提供了检查字段是否已初始化的工具,它可以抛出并返回默认值。

否则,我不知道编译器中有任何工具可以进行此类测试。但是,如果您编写测试(无论如何您都应该进行测试!),那么您的测试可以进行此类验证。

请注意,我首先想到了探查器,但这需要一个测试,无论如何都会告诉您您是否正确,探查器可以告诉您初始化已被调用,但您不知道是否在所有情况下都发生了这种情况。

但是,如 Ed S. 所述,要真正在编译时强制执行此类初始化(假设您确实需要它),最好的方法可能是使用工厂。这样所有丑陋的初始化代码都被隐藏起来了。

于 2014-06-03T10:36:37.687 回答