#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
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){} };
为避免继承构造函数冲突,可以通过显示定义来阻止隐式生成的继承构造函数。