簡體   English   中英

虛擬化繼承抽象類的參數化構造函數

[英]Parametrized constructor in virtually inheriting abstract class

我有一個經典的虛擬繼承鑽石:

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();
}

我在BC使用NULL,因為它們是抽象類,所以在它們的構造函數中永遠不會調用A ctor。 有沒有更好的方法來做,否則在構造函數中指定NULL或在A聲明無參數構造函數? 我希望使用參數調用構造函數,因此只應在抽象類中允許A() {} ctor。

您可以將A更改為:

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

然后B(): A() {}C(): A() {}可以工作,但D(const char*): A() {}不會。 但這真的很尷尬。 我堅持你目前正在使用的NULL

不過,這確實是一個有趣的案例。 我認為沒有技術上的理由說明為什么你必須BCA指定一個構造函數,因為它們永遠不會被創建,無論是誰繼承它們都會初始化A

您可以在A(const char*)指定默認參數 A(const char*)

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

但是,這也將允許D避免A()

我正在關閉這個,因為嚴格的答案可能不存在。 IMO最好的解決方法是

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

class A {
protected:
    A(const AbstractPlaceholder &ap) {}
    A(const char *x) { ... }
};

你的方法的變化將是

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

從而添加更有意義的診斷。


但是,您可能希望明確允許xNULL (作為通過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();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM