c++ - 命名規則 - 調用超類構造函數的規則是什麼?




c++命名規則 (6)

從子類調用超類構造函數的C ++規則是什麼?

例如,我知道在Java中,您必須將其作為子類構造函數的第一行(如果您不這樣做,則假定隱式調用no-arg超級構造函數 - 如果缺少,則會給出編譯錯誤) 。


在C ++中,所有超類和成員變量的無參構造函數都會在進入構造函數之前調用。 如果你想傳遞它們的參數,這個叫做“構造函數鏈接”的單獨語法如下所示:

class Sub : public Base
{
  Sub(int x, int y)
  : Base(x), member(y)
  {
  }
  Type member;
};

如果此時運行的任何內容拋出,先前完成構建的基礎/成員將調用它的析構函數,並將異常重新拋出給調用者。 如果要在鏈接期間捕獲異常,則必須使用函數try塊:

class Sub : public Base
{
  Sub(int x, int y)
  try : Base(x), member(y)
  {
    // function body goes here
  } catch(const ExceptionType &e) {
    throw kaboom();
  }
  Type member;
};

在這種形式下,請注意try塊函數的主體,而不是在函數體內; 這允許它捕獲由隱式或顯式成員和基類初始化引發的異常,以及在函數的主體期間。 但是,如果函數catch塊不會引發其他異常,則運行時將重新拋出原始錯誤; 初始化期間的異常不能被忽略。


在C ++中,有一個構造函數初始化列表的概念,您可以並且應該調用基類的構造函數,並在其中初始化數據成員。 初始化列表出現在冒號後面的構造函數簽名之後,並且位於構造函數的主體之前。 假設我們有一個A類:


class A : public B
{
public:
  A(int a, int b, int c);
private:
  int b_, c_;
};

然後,假設B有一個接受int的構造函數,A的構造函數可能如下所示:


A::A(int a, int b, int c) 
  : B(a), b_(b), c_(c) // initialization list
{
  // do something
}

如您所見,基類的構造函數在初始化列表中調用。 順便說一句,初始化初始化列表中的數據成員優於為構造函數的body中的b_和c_賦值,因為這樣可以節省額外的賦值成本。

請記住,數據成員總是按照它們在類定義中聲明的順序進行初始化,而不管它們在初始化列表中的順序如何。 為了避免在數據成員彼此依賴時可能出現的奇怪錯誤,您應該始終確保成員順序在初始化列表和類定義中相同。 基於同樣的原因,基類構造函數必須是初始化列表中的第一項。 如果完全忽略它,那麼將自動調用基類的默認構造函數。 在這種情況下,如果基類沒有默認構造函數,那麼將會出現編譯器錯誤。


如果在基礎構造函數中有默認參數,則基類將自動調用。

using namespace std;

class Base
{
    public:
    Base(int a=1) : _a(a) {}

    protected:
    int _a;
};

class Derived : public Base
{
  public:
  Derived() {}

  void printit() { cout << _a << endl; }
};

int main()
{
   Derived d;
   d.printit();
   return 0;
}

輸出是:1


如果沒有參數,基類構造函數會自動調用。 如果要使用參數調用超類構造函數,則必須使用子類的構造函數初始化列表。 與Java不同,C ++支持多重繼承(無論好壞),所以基類必須以名稱引用,而不是“super()”。

class SuperClass
{
    public:

        SuperClass(int foo)
        {
            // do something with foo
        }
};

class SubClass : public SuperClass
{
    public:

        SubClass(int foo, int bar)
        : SuperClass(foo)    // Call the superclass constructor in the subclass' initialization list.
        {
            // do something with bar
        }
};

關於herehere的構造函數初始化列表的更多信息。


每個人都通過初始化列表提到了構造函數調用,但沒有人說可以從派生成員的構造函數體中顯式調用父類的構造函數。 例如,查看問題從子類的構造函數體調用基類的構造函數 。 重點是,如果您在派生類的主體中使用對父類或超類構造函數的顯式調用,實際上這只是創建父類的實例,而不是在派生對像上調用父類構造函數。 在派生類的對像上調用父類或超類構造函數的唯一方法是通過初始化列表,而不是在派生類構造函數體中。 所以也許它不應該被稱為“超類構造函數調用”。 我在這裡提供了這個答案,因為有人可能會感到困惑(就像我一樣)。


當一個類從多個類派生時,沒有人提到構造函數調用的順序。 序列如派生類所述。





constructor