赞
踩
当类B继承于类A的时候,它会继承类A中的数据成员与普通成员函数。但是某些成员函数是无法被继承下来的,比如类A(基类)中的合成构造函数(包括构造、析构、拷贝等等)。因此,类B在初始化类A的成员时候,需要显示调用类A的构造函数以达到初始化的目的。如下示例:
class A{ private: int m_a; public: A(const int &a) :m_a(a) {} A(const A &a){} }; class B : public A{ private: int m_b; public: B(const int &a) :A(a) //显示调用基类A的构造函数 {} };
类B显示调用类A的构造函数 A(a) 来初始化类A中的数据成员m_a。该示例中,类A仅有一个构造函数,若类A有多个构造函数,而类B(派生类)中仅增加了一些成员函数时, 我们会发现,类B中的所有操作(构造)函数都是为了初始化类A的成员, 这时候你会发现费了这么多精力,都耗在了初始化中,这或许并不是我们的初衷。
#include <iostream> using namespace std; class A{ private: int m_a; public: A(const int &a, const double &b){} A(const int &a){} A(const float &f){} A(const double &d){} A(const A &a) = delete; }; class B : public A{ private: int m_b; public: B(const int &a, const double &b) :A(a, b) {} B(const int &a) :A(a) {} B(const float &f) :A(f) {} B(const double &d) :A(d) {} //NEW ADD void test(){} }; int main() { return 0; }
现在基类A有4个构造函数,派生类B没有新增成员,然而在派生类B中却不得不对基类A的各构造函数进行显示调用以达到初始化基类A中数据成员的目的。 在C++98前,这是迫不得已的,但是C+11中,我们可以使用 using 声明来解决该问题。
using是c++中的一个关键字,它常常使用于以下3种场景,分别是:
(1) 将命名空间(namespace)中的特定成员引入当前作用域 .
(2) 将命名空间(namespace)的所有成员带入当前作用域 .
(3) 将基类的方法(函数)或变量引入当前类的范围.
using声明(using declaration)的使用形式如下:
using namespace::name;
当然,using的作用范围不仅仅是这些,比如C++11中,使用using来进行别名声明(类似typedef的作用)。这个后面专门出一篇博文进行说明。
将命名空间std中的数据成员cout和endl引入到当前main函数的作用域中。
#include <iostream>
int main()
{
int a = 10;
using std::cout;
using std::endl;
cout << "a: " << a << endl;
}
将std命名空间中的所有成员引入当前作用域。
#include <iostream>
using namespace std;
int main()
{
int a = 10;
cout << "a: " << a << endl;
}
#include <iostream> #include <string> using namespace std; class T { public: void t() { cout << "T ..." << endl; } void h() { cout<<"T::h"<<endl; } }; class U : public T{ public: using T::t; void t(const string &s) { cout << "U ... " << s << endl; t(); } using T::h; }; int main() { U u; u.t("hello world."); U h; h.h(); return 0; }
打印结果:
U ... hello world.
T ...
T::h
注意,每条using声明引入一个数据成员或成员函数,可以在一行写1个using声明,也可以写多个声明,但是每个成员都需要有自己的using声明,并且以分号结束。eg:
using T::f; //一行一条using声明
using T::f; using T::m; using T::h; //一行多条using声明
一条using声明可以出现在全局作用域、局部作用域、命名空间作用域及类的作用域中。
基于using的这些功能特性,C++11对using的功能进行了扩展,使其基类的构造函数也支持继承。如下示例代码:
#include <iostream> #include <string> using namespace std; class T { public: T() = default; T(const int &a){} T(const int &a, float &b){} }; class U : public T{ public: using T::T; //using声明基类T的构造函数 }; int main() { U u; return 0; }
现在派生类U中不需要再显示调用基类T的所有构造函数,通过using T::T,将基类T中的系列构造函数传递到派生类U中。注意:继承构造函数只能初始化基类中的数据成员,对于派生类中的数据成员,仍然需要自行处理,可以使用 快速初始化成员变量 新特性来进行初始化。如下:
class T
{
public:
T() = default;
T(const int &a){}
T(const int &a, float &b){}
};
class U : public T{
public:
using T::T; //using声明基类T的构造函数
int m_b{1}; //C++11新特性-快速初始化成员变量。
};
(1) 如果基类的构造函数是private属性,那么派生类无法声明基类的继承构造函数。
class T
{
private: //基类构造函数声明为private
T() = default;
T(const int &a){}
T(const int &a, float &b){}
};
class U : public T{
public:
using T::T; //using声明基类T的构造函数
int m_b{1};
};
当前基类T中构造函数修饰为private,此时派生类U中的继承构造函数声明无效,会报错:
D:\XXXX\XXX\main.cpp:13: 'U::U()' is implicitly deleted because the default definition would be ill-formed:
class U : public T{
^
(2) 如果派生类是是以虚继承的方式从基类进行派生,在派生类中也无法声明基类的继承构造函数。
(3) 当派生类是多继承方式时候,可能会出现继承类冲突隐患。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。