4

我有一个经典的虚拟继承钻石:

class A {
protected:
    A(const char *x) { ... }
}

class B: public virtual A {
protected:
    B(): A(NULL) { ... }
public:
    virtual void foo() = 0;
}

class C: public virtual A {
protected:
    C(): A(NULL) { ... }
public:
    virtual void bar() = 0;
}

class D: public B, public C {
public:
    D(const char *x): A(x) { ... }
    void foo();
    void bar();
}

我使用 NULLB并且C因为它们是抽象类,所以A永远不会在它们的构造函数中调用 ctor。NULL除了在构造函数中指定或在中声明无参数构造函数之外,还有更好的方法A吗?我希望使用参数调用构造函数,因此A() {}应该只允许在抽象类中使用 ctor。

4

4 回答 4

0

您可以更改A为:

class A {
private:
    A() {};
    friend class B;
    friend class C;
protected:
    A(const char *x) { }
};

然后B(): A() {}andC(): A() {}会工作,但D(const char*): A() {}不会。但这真的很尴尬。我会坚持NULL你目前使用的。

不过,这确实是一个有趣的案例。我想不出任何技术上的理由为什么你必须Ain指定一个构造函数,B并且C因为它们永远不会被创建,并且继承它们的人A无论如何都会初始化。

于 2011-10-09T13:01:00.337 回答
0

您可以在中指定默认参数A(const char*)

class A {
protected:
    A(const char *x = 0) { ... }
                    ^^^^
};

但是,这也将允许D避免A()

于 2011-10-09T13:02:08.580 回答
0

我正在关闭这个,因为正确的答案可能不存在。IMO 最好的解决方法是

struct AbstractPlaceholder {
    AbstractPlaceholder() {
        assert(false);
    }
};

class A {
protected:
    A(const AbstractPlaceholder &ap) {}
    A(const char *x) { ... }
};
于 2012-01-13T23:21:44.877 回答
0

您的方法的一种变体是

class A {
protected:
    A(const char *x = NULL) {
      assert(x && "A mustn't be default constructed!");
    }
};

从而增加了更有意义的诊断。


但是,您可能希望明确地允许x存在NULL(作为通过 的合法结构C),然后您可以使用Maybe类型。

template <typename T> class Maybe {
  T const t; // must be default constructible!
  bool const invalid;
  public:
    Maybe() : t(), invalid(true) {}
    Maybe(T t) : t(t), invalid(false) {}
    bool nothing() const {
      return invalid;
    }
    T just() const {
      assert(!invalid);
      return t;
    }
};

然后你可以将你的构造函数更改为

A::A(Maybe<const char*> mx) {
  // either
  assert(!mx.nothing());
  // or
  mx.just();
}
于 2012-01-13T23:44:31.303 回答