委托构造函数

 

 

 

 

#include <iostream>
using namespace std;
class A
{
private:
        int i=5;
        string str="init value";
public:
        A(){
                str="A()";
                i=99;
        }
        A(int ii):A(){
        //不能写成AA(int ii):A(),i(ii)
        //委托构造函数不能再利用初始化器初始化其他数据成员
                i=ii;
        }
        void show(){
                cout<<"i="<<i<<",str="<<str<<endl;
        }
};
int main()
{
        A a(10);
        a.show();
}

 

 

root@ubuntu:~/c++# g++ -std=c++11   delegate.cpp -o delegate
root@ubuntu:~/c++# ./delegate
i=10,str=A()

 

#include <iostream>
using namespace std;
class A
{
private:
        int i=5;
        int b;
        string str="init value";
public:
        A(){
                str="A()";
                i=99;
        }
        A(int ii):A(),b(10){
        //不能写成AA(int ii):A(),i(ii)
        //委托构造函数不能再利用初始化器初始化其他数据成员
                i=ii;
        }
        void show(){
                cout<<"i="<<i<<",str="<<str<<endl;
        }
};
int main()
{
        A a(10);
        a.show();
}

 

 

 

root@ubuntu:~/c++# g++ -std=c++11   delegate.cpp -o delegate
delegate.cpp: In constructor ‘A::A(int)’:
delegate.cpp:14:20: error: mem-initializer for ‘A::b’ follows constructor delegation
  A(int ii):A(),b(10){
                    ^
root@ubuntu:~/c++#

但是要注意不要递归委托:例如

#include <iostream>  
using namespace std;  
class A  
{  
public:  
    A(string ss):A(555){  
        str=ss;  
    }  
    
    A(int ii):A("OK"){  
        i=ii;             
    }
      
    /* A(string) 和 A(int) 构造函数就形成了递归委托*/
    void show(){  
        cout<<"i="<<i<<",str="<<str<<endl;  
    }  
    
private:  
    int i=5;  
    string str="init";  
}; 

int main()  
{  
    A a(10);  
    a.show();  
} 

 

 

root@ubuntu:~/c++# g++ -std=c++11   delegate.cpp -o delegate
root@ubuntu:~/c++# ./delegate 
Segmentation fault (core dumped)

 

 root@ubuntu:~/c++# ./delegate
base:4.5
base:4.5
derived:4
root@ubuntu:~/c++# cat delegate.cpp 
#include <iostream>
using namespace std;
 
struct Base
{
    
    void f(double i){
   cout<<"base:"<<i<<endl;}
};
 
struct Derived: Base
{
    
    using Base::f;
    void f(int i){
   cout<<"derived:"<<i<<endl;}
};
 
int main()
{
    
    Base b;
    b.f(4.5);       //base:4.5
 
    Derived d;
    d.f(4.5);     
    d.f(4);       //derived:4.5
    return 0;
} 

这里我们使用using声明,这样派生类中就拥有了两个版本的重载函数 f 。

 

 

root@ubuntu:~/c++# g++ -std=c++11   delegate.cpp -o delegate
root@ubuntu:~/c++# ./delegate
base:4.5
base:4.5
derived:4

 

继承构造函数

为什么需要继承构造函数

子类为完成基类初始化,在C++11之前,需要在初始化列表调用基类的构造函数,从而完成构造函数的传递。如果基类拥有多个构造函数,那么子类也需要实现多个与基类构造函数对应的构造函数。

class Base
{
public:
    Base(int va) :m_value(va), m_c(‘0’){}
    Base(char c) :m_c(c) , m_value(0){}
private:
    int m_value;
    char m_c;
};

class Derived :public Base
{
public:
    //初始化基类需要透传基类的各个构造函数,那么这是很麻烦的
    Derived(int va) :Base(va) {}
    Derived(char c) :Base(c) {}
};

 如何继承父类的构造函数

书写多个派生类构造函数只为传递参数完成基类的初始化,这种方式无疑给开发人员带来麻烦,降低了编码效率。从C++11开始,推出了继承构造函数(Inheriting Constructor),使用using来声明继承基类的构造函数。

#include <iostream>
using namespace std;

class Base
{
public:
    Base(int va) :m_value(va), m_c('0') {}
    Base(char c) :m_c(c), m_value(0) {}
    void show()
    {cout << m_value << " " << m_c <<endl;}
private:
    int m_value;
    char m_c;
};

class Derived :public Base
{
public:
    //使用继承构造函数
    using Base::Base;
};

int main()
{


    Derived d1(99);
    d1.show();
    Derived d2('d');
    d2.show();
    return 0;
};

 

root@ubuntu:~/c++# g++ -std=c++11   delegate.cpp -o delegate
root@ubuntu:~/c++# ./delegate
99 0
0 d
通过 using Base::Base 把基类构造函数继承到派生类中,不再需要书写多个派生类构造函数来完成基类的初始化。C++11 标准规定,继承构造函数与类的一些默认函数(默认构造、析构、拷贝构造函数等)一样,是隐式声明,如果一个继承构造函数不被相关代码使用,编译器不会为其产生真正的函数代码。这样比总是需要定义派生类的各种构造函数更加节省目标代码空间。


 

1.3 注意事项

(1)继承构造函数无法初始化派生类数据成员,继承构造函数的功能是初始化基类,对于派生类数据成员的初始化则无能为力。解决的办法主要有两个:

  • 可以通过 =、{} 对非静态成员快速地就地初始化,以减少多个构造函数重复初始化变量的工作,注意初始化列表会覆盖就地初始化操作

 
#include <iostream>
using namespace std;

class Base
{
public:
    Base(int va) :m_value(va), m_c('0') {}
    Base(char c) :m_c(c), m_value(0) {}
    void show()
    {cout << m_value << " " << m_c <<endl;}
private:
    int m_value;
    char m_c;
};

class Derived :public Base
{
public:
    //使用继承构造函数
    using Base::Base;
    void show()
    {
         Base::show();
            cout <<  m_value2 << "   " <<  m_value3 <<endl;}
private:
    int m_value2=299;
    int m_value3{399};
};

int main()
{


    Derived d1(99);
    d1.show();
    Derived d2('d');
    d2.show();
    return 0;
};

 


 
root@ubuntu:~/c++# g++ -std=c++11   delegate.cpp -o delegate
root@ubuntu:~/c++# ./delegate 
99 0
299   399
0 d
299   399

 

  • 新增派生类构造函数,使用构造函数初始化列表初始化
#include <iostream>
using namespace std;

class Base
{
public:
    Base(int va) :m_value(va), m_c('0') {}
    Base(char c) :m_c(c), m_value(0) {}
    void show()
    {cout << m_value << " " << m_c <<endl;}
private:
    int m_value;
    char m_c;
};

class Derived :public Base
{
public:
    //使用继承构造函数
    using Base::Base;
    //新增派生类构造函数
    Derived(int a,int b):Base(a),m_value2(b){}
    void show()
    {
         Base::show();
         cout <<  m_value2 << "   " <<  m_value3 <<endl;
    }
private:
    int m_value2=299;
    int m_value3{399};
};

int main()
{


    Derived d1(99,100);
    d1.show();
  }  

 

root@ubuntu:~/c++# ./delegate 
99 0
100   399
root@ubuntu:~/c++# 

 

#include <iostream>
using namespace std;

class Base
{
public:
    Base(int va) :m_value(va), m_c('0') {}
    Base(char c) :m_c(c), m_value(0) {}
    void show()
    {cout << m_value << " " << m_c <<endl;}
private:
    int m_value;
    char m_c;
};

class Derived :public Base
{
public:
    //使用继承构造函数
    using Base::Base;
    //新增派生类构造函数
    Derived(int a,int b):Base(a),m_value2(b)
    {
         m_value3=200;
    }
    void show()
    {
         Base::show();
         cout <<  m_value2 << "   " <<  m_value3 <<endl;
    }
private:
    int m_value2=299;
    int m_value3{399};
};

int main()
{


    Derived d1(99,100);
    d1.show();
    return 0;
}

 

root@ubuntu:~/c++# g++ -std=c++11   delegate.cpp -o delegate
root@ubuntu:~/c++# ./delegate 
99 0
100   200

 

多继承的情况下,继承构造函数会出现“冲突”的情况,因为多个基类中的部分构造函数可能导致派生类中的继承构造函数的函数名与参数相同,即函数签名。
 
class A
{
public:
    A(int i){}
};

class B
{
public:
    B(int i){}
};

class C : public A,public B
{
public:
    using A::A;
    using B::B;  //编译出错,重复定义C(int)
    
    //显示定义继承构造函数C(int)
    C(int i):A(i),B(i){}
};

为避免继承构造函数冲突,可以通过显示定义来阻止隐式生成的继承构造函数。

 

 

posted on 2021-07-28 15:30  tycoon3  阅读(144)  评论(0编辑  收藏  举报

导航