• C++11继承构造函数在类中的使用


    概念

    继承构造函数在C++11特性中随之提及,其大概可以理解为:
    解决了派生类无法直接使用基类中的构造函数的这一问题
    正常情况下,基类定义了自己的构造函数,派生类公有继承基类后,由于派生类隐藏了基类的同名函数,是无法直接使用基类的同名函数的(这里针对于普通函数)。如下所示的例子:
    基类Base的定义

    class Base
    {
    public:
    	Base(int a):m_a(a) {}
    	Base(int a, double b):m_a(a),m_b(b) {}
    	Base(int a, double b, string c) :m_a(a), m_b(b), m_c(c) {}
    private:
    	int m_a;
    	double m_b;
    	string m_c;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    派生类Derived

    class Derived :public Base 
    {
    public:
    	
    private:
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上述的派生类Derived 中没有定义自己的构造函数,虽然是公有继承的基类Base,但是不能直接使用基类的构造函数构造自己的对象。像下面这样是错误的,无法编译通过:
    在主函数中的使用:

    int main()
    {
    	Derived d(12,4.56,"");//编译报错,没有相应的构造函数
    }
    
    • 1
    • 2
    • 3
    • 4

    衍生问题

    上述也引发一个问题,若是像下面这样写,也是不正确的。

    int main()
    {
    	Derived d;//编译报错,尝试引用已删除的函数
    }
    
    • 1
    • 2
    • 3
    • 4

    Derived 类中没有写任何函数,直接使用派生类默认的构造函数。按理这里应该是会调用自己的默认构造函数,但编译报错:尝试引用已删除的函数。这是因为派生类继承基类之后,会将派生类默认生成的构造函数删除吗?求解!!!
    原因:Derived 类创建对象d时,先调用基类构造函数,再调用派生类构造函数,基类中已经显式的定义了三个有参构造函数,系统会将默认的无参构造函数删除,所以创建Derived 对象d的时候,调用基类构造函数,没有找到匹配的无参构造函数,已经被系统删除了。
    但是改为下面这样:

    int main()
    {
    	Derived d();//编译通过,但有警告:未调用原型函数(是否是有意用变量定义的?)
    }
    
    • 1
    • 2
    • 3
    • 4

    这是为什么呢????
    原因:单独将Derived d();当作一个函数的声明。
    同样如果是一个没有继承关系的类,可以这样创建类对象:

    class Base
    {
    public:
    private:
    };
    
    int main()
    {
    	Base d();//编译通过,这里也可以这样写 Base d;同样也会编译通过
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    创建对象时,调用的默认的无参构造函数。编译器会为没有显示创建构造函数,析构函数,拷贝构造函数(复制构造函数)以及赋值构造函数(赋值运算符重载)的类自动生成这些函数。

    使用示例

    下面是继承构造函数的使用。也就是派生类可以调用基类的构造函数的来创建自己的对象的方式。
    依旧是最初的例子:

    class Base
    {
    public:
    	Base(int a):m_a(a) {}
    	Base(int a, double b):m_a(a),m_b(b) {}
    	Base(int a, double b, string c) :m_a(a), m_b(b), m_c(c) {}
    private:
    	int m_a;
    	double m_b;
    	string m_c;
    };
    
    class Derived :public Base 
    {
    public:
    	using Base::Base;//使用基类的构造函数
    private:
    
    };
    int main()
    {
    	//使用基类的构造函数
    	Derived d(12,4.56,"");
    	Derived e(2);
    	Derived f(4,5.67);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    此例中派生类可以使用基类的构造函数来创建对象。方法是在派生类中采用using 声明的方式。
    像该例中的using Base::Base;使用时就是:
    using 类名::函数名;

    注意

    以上继承构造函数在使用时,若是派生类中定义了自己的成员变量,继承构造函数不会去初始化派生类定义的成员变量。且上述using 类名::函数名; 调用基类构造函数的方法也适用于函数。

    扩展使用(函数)

    上面提到这种using声明的方式也可以在函数上使用,下面便是一个示例。

    示例代码

    依旧采用文章中提到的示例代码稍作修改。

    #include 
    #include 
    using namespace std;
    
    class Base
    {
    public:
    	Base(int a):m_a(a) {}
    	Base(int a, double b):m_a(a),m_b(b) {}
    	Base(int a, double b, string c) :m_a(a), m_b(b), m_c(c) {}
    
    	void Fun() { cout << "Base::Fun()" << endl; }
    
    private:
    	int m_a;
    	double m_b;
    	string m_c;
    };
    
    class Derived :public Base 
    {
    public:
    	using Base::Base;//使用基类的构造函数
    
    	void Fun(int a) { cout << "Derived::Fun()" << endl; }//隐藏
    private:
    
    };
    
    int main()
    {
    	//使用基类的构造函数
    	Derived d(12,4.56,"");
    	Derived e(2);
    	Derived f(4,5.67);
    
    	//使用基类的函数
    	d.Fun();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    可以看到在使用继承构造函数的基础上,在基类和派生类中新增了函数Fun,两个函数分别位于基类与派生类中,函数名相同,参数不同,此为隐藏关系。更多关于隐藏的介绍可以查看我之前的博文,搜索关键字——隐藏
    这里通过d.Fun()调用父类的函数Fun(),但是整个代码是无法通过编译的,要想通过派生类对象调用父类的同名函数需要使用相应的using 类名::函数名来声明
    下面稍作修改,是正确的代码:

    #include 
    #include 
    using namespace std;
    
    class Base
    {
    public:
    	Base(int a):m_a(a) {}
    	Base(int a, double b):m_a(a),m_b(b) {}
    	Base(int a, double b, string c) :m_a(a), m_b(b), m_c(c) {}
    
    	void Fun() { cout << "Base::Fun()" << endl; }
    
    private:
    	int m_a;
    	double m_b;
    	string m_c;
    };
    
    class Derived :public Base 
    {
    public:
    	using Base::Base;//使用基类的构造函数
    	using Base::Fun;//使用基类的同名函数
    	
    	void Fun(int a) { cout << "Derived::Fun()" << endl; }//隐藏
    private:
    
    };
    
    int main()
    {
    	//使用基类的构造函数
    	Derived d(12,4.56,"");
    	Derived e(2);
    	Derived f(4,5.67);
    
    	//使用基类的函数
    	d.Fun();
    	d.Base::Fun();//与上一行写法都可以,有两种调用方式
    	
    	e.Fun(2);//使用派生类自己的函数
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    上述代码可以编译通过。

    输出结果

    输出结果为:
    在这里插入图片描述

    注意

    在派生类中引入using声明之后,d.Fun();与d.Base::Fun();都可以达到调用基类的Fun()函数的作用。
    在没有引入using声明时,可以采用d.Base::Fun();这种调用方式。d.Base::Fun();的调用已经指明了调用的是基类中的函数。
    下面是不引入using声明的基类同名函数Fun()调用示例:

    #include 
    #include 
    using namespace std;
    
    class Base
    {
    public:
    	Base(int a):m_a(a) {}
    	Base(int a, double b):m_a(a),m_b(b) {}
    	Base(int a, double b, string c) :m_a(a), m_b(b), m_c(c) {}
    
    	void Fun() { cout << "Base::Fun()" << endl; }
    
    private:
    	int m_a;
    	double m_b;
    	string m_c;
    };
    
    class Derived :public Base 
    {
    public:
    	using Base::Base;//使用基类的构造函数
    
    	void Fun(int a) { cout << "Derived::Fun()" << endl; }//隐藏
    private:
    
    };
    
    int main()
    {
    	//使用基类的构造函数
    	Derived d(12,4.56,"");
    	Derived e(2);
    	Derived f(4,5.67);
    
    	//使用基类的函数
    	d.Base::Fun();//编译正确
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
  • 相关阅读:
    OSPF——基本概念1(邻居建立)
    数据清洗工具flashtext,效率直接提升了几十倍数
    Java、servlet、Tomcat实现文件上传操作
    window.open在 ios safari中打开新页面失败
    如何选择适合的开源框架来构建微服务架构?
    服务器开放敏感端口
    U-Mail邮件服务器软件,企业自建邮件服务器的最佳选择
    Java程序设计——注解(Java高级应用)
    2003. 每棵子树内缺失的最小基因值 DFS
    【云笔记篇】Microsoft OneNote笔记插件推荐OneMore
  • 原文地址:https://blog.csdn.net/blqzj214817/article/details/126707521