c++11的構造函數繼承


https://en.cppreference.com/w/cpp/language/using_declaration

在[Inheriting constructors]這一節.

其實叫做"基類的構造函數前置"比較好.

像mystring繼承自string類,但仍然是提供字符串功能.new的時候仍舊希望保留舊有的初始化傳參方式.這時候在mystring里一一再實現(調用基類)就比較麻煩.

但在c++11之前只能這樣.

c++11之前的默認構造方式(淡然c++11之后還是)是,先把各個基類的默認初始化函數調用一遍.然后對派生字段做默認初始化.

c++11之前用戶定義的構造函數,可以在初始化列表里調用基類的構造函數,同時可以傳參.基類的構造函數仍舊是先調用一遍.

c++11開始,就有了using Base::Base;的寫法,當編譯器在派生類里找不到相應的構造函數時,就會在這個基類Base里找.在此之后,會調用其它基類的默認構造函數,派生類的字段則是賦值初始化.(這也是c++11之后引入的)

 

Inheriting constructors

If the using-declaration refers to a constructor of a direct base of the class being defined (e.g. using Base::Base;), all constructors of that base (ignoring member access) are made visible to overload resolution when initializing the derived class.

If overload resolution selects an inherited constructor, it is accessible if it would be accessible when used to construct an object of the corresponding base class: the accessibility of the using-declaration that introduced it is ignored.

If overload resolution selects one of the inherited constructors when initializing an object of such derived class, then the Base subobject from which the constructor was inherited is initialized using the inherited constructor, and all other bases and members of Derived are initialized as if by the defaulted default constructor (default member initializers are used if provided, otherwise default initialization takes place). The entire initialization is treated as a single function call: initialization of the parameters of the inherited constructor is sequenced-before initialization of any base or member of the derived object.

 

翻譯下來大概是:

using Base::Base;的用途:

>派生類初始化時,基類的所有構造函數對overload resolution可見,無視權限修飾符.

>如果基類的某個構造函數被選中,那么先用它初始化那個基類,然后"其它的基類"和"派生字段"被初始化就像使用默認的default 構造函數.(采用提供的default initializers,若用戶未提供,則發生默認初始化).

>那個基類的構造函數總是最先被調用.

下面是例子代碼:

struct B1 {  B1(int, ...) { } };
struct B2 {  B2(double)   { } };
 
int get();
 
struct D1 : B1 {
  using B1::B1;  // inherits B1(int, ...)
  int x;
  int y = get();
};
 
void test() {
  D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4),
                 // then d.x is default-initialized (no initialization is performed),
                 // then d.y is initialized by calling get()
  D1 e;          // Error: D1 has no default constructor
}
 
struct D2 : B2 {
  using B2::B2; // inherits B2(double)
  B1 b;
};
 
D2 f(1.0);       // error: B1 has no default constructor
 
         

As with using-declarations for any other non-static member functions, if an inherited constructor matches the signature of one of the constructors of Derived, it is hidden from lookup by the version found in Derived. If one of the inherited constructors of Base happens to have the signature that matches a copy/move constructor of the Derived, it does not prevent implicit generation of Derived copy/move constructor (which then hides the inherited version, similar to using operator=).

翻譯:簡單的說,就是using Base:Base之后,派生類可以重載某一個版本來覆蓋掉. 基類的copy/move constructor不受這個using的影響,派生類如果沒有copy/move constructor,編譯器會生成默認的,不會用基類的.

例子代碼:

struct B1 {   B1(int); };
struct B2 {   B2(int); };
 
struct D2 : B1, B2 {
  using B1::B1;
  using B2::B2;
  D2(int);   // OK: D2::D2(int) hides both B1::B1(int) and B2::B2(int)
};
D2 d2(0);    // calls D2::D2(int)

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM