c++一个类能继承多个类吗_c++中类继承多个类 - CSDN
精华内容
参与话题
  • C++多继承

    万次阅读 2015-07-19 23:07:39
    c++中一个可以从多个基类中派生(即可以有多个父类),这就是多继承。多继承的方式主要有两种:1. 简单版本 C会同时拥有A和B的特性(属性和方法,也就是两个的所有成员)。这种方式很简单这里就不多说,...

    在写这一主题的文章之前,在网上找到一篇很非常好的文章C++之继承与多态。就没有必要做重复造轮子的事件了,那就从这篇文章开始吧!

    在c++中一个类可以从多个基类中派生(即可以有多个父类),这就是多继承。多继承的方式主要有两种:

    1. 简单版本

    这里写图片描述

    类C会同时拥有类A和类B的特性(属性和方法,也就是两个类的所有成员)。这种方式很简单这里就不多说,主要讲下面这种方式。


    2. 复杂版本


    这里写图片描述

    同样的,这个结构中类C也会同时拥有类A和类B的特性,但这就会有一个问题,类B1和B2都继承自A,那么类C的对象会同时包含两个A的对象。这样就会带来很多歧义性。

    我们看一个典型的例子“沙发-床”:

    这里写图片描述
    类的关系图

    代码:

    #pragma once
    
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Furniture
    {
    public:
        Furniture(void) : m_weight(0){}
        Furniture(double weight) : m_weight(weight){}
        ~Furniture(void){}
    
        double GetWeight() const { return m_weight; }
        void SetWeight(double val) { m_weight = val; }
    
    private:
        double m_weight;
    
    };
    
    class Bed : public Furniture
    {
    public:
        Bed() : Furniture(), m_second(0) {}
        Bed(double weight, int second) : Furniture(weight), m_second(second){}
    
        void Sleep(int second) 
        {
            m_second = second;
            cout << "休息" << m_second << "秒..."<< endl;
        }
    
    
    private:
        int m_second;
    
    };
    
    class Sofa : public Furniture
    {
    public:
        Sofa() : Furniture() {}
        Sofa(double weight) : Furniture(weight){}
    
        void WatchTV(string  programme)
        {
            cout << "正在看" << programme << "节目..." << endl;
        }
    };
    
    class SleepSofa : public Bed, public Sofa
    {
    public:
        SleepSofa() : Bed(), Sofa() {}
        SleepSofa(double weight, int second) : Bed(weight, second), Sofa(weight) {}
    
        void FoldOut()
        {
            cout << "展开沙发当床用." << endl;
            Sleep(360);
        }
    };

    SleepSofa类继承自Bed和Sofa两个类,因此,SleepSofa类拥有这两个类的特性,但在实际编码中会存在如下几个问题。

    1.SleepSofa类该如何定义?

    Class SleepSofa : public Bed, public Sofa
    {
        …
    }
    

    构造顺序为:Bed sofa sleepsofa (也就是书写的顺序)

    2.Bed和Sofa类都继承自Furniture,都有Weight属性也都有GetWeight和SetWeight方法,在SleepSofa类中使用这些属性和方法时,如何确定调用的是哪个类的成员?

    我们看一下测试样例:

    void Test()
    {
        SleepSofa sleepSofa;
        sleepSofa.SetWeight(55);
        double weight = sleepSofa.GetWeight();
    }

    这时会有以下错误:

    .cpp(76): error C3861: ‘SetWeight’: identifier not found
    error C2385: ambiguous access of ‘GetWeight’

    就是说SetWeight和GetWeight是有歧义的。

    解决方法:
    (1). 可以使用完全限定名(即加上类的作用域)的方式,比如:

    SleepSofa sleepSofa;
    sleepSofa.Bed::SetWeight(55);
    sleepSofa.Sofa::SetWeight(80);
    

    这时可以看到sleepSofa对象有两个Furniture对象。如下:

    这里写图片描述

    (2). 虚继承
    倘若,我们定义一个SleepSofa对象,让我们分析一下它的构造过程:它会构造Bed类和Sofa类,但Bed类和Sofa类都有一个父类,因此Furniture类被构造了两次,这是不合理的,因此,我们引入了虚继承的概念。

    class Furniture{……};
    
    class Bed : virtual public Furniture{……}; // 这里我们使用虚继承
    
    class Sofa : virtual public Furniture{……};// 这里我们使用虚继承
    
    class SleepSofa : public Bed, public Sofa {……};
    

    这样,Furniture类就只会构造一次,sleepSofa对象只会包含一个Furniture对象。
    我们看一下测试样例:

    SleepSofa sleepSofa;
    sleepSofa.SetWeight(80);
    

    这时我们Debug模式可以看到SleepSofa的m_weight值都是80。

    这里写图片描述

    这里虽然显示着两个Furniture对象,但其实指向的是同一个对象。我们可以看看它们的地址都是一样的。

    这里写图片描述



    总结

    1. 在程序设计中最好不要出现多继承,要有也是继承多个作为接口使用抽象类(只声明需要的功能,没有具体的实现)。因为出现一般的多继承本身就是一种不好的面向对象程序设计。
    2. 在出现版本2的多继承时使用虚继承的方式。


    展开全文
  • C++类——多继承

    千次阅读 2018-07-11 19:29:28
      如果一个派生多个基类继承, 则称为多继承。 多继承的声明: class 派生类名:访问控制 基类名1, 访问控制 基类名2, ... { 成员列表 } 注意: 多个基类的派生的构造函数执行的顺序与单继承的...
    多继承的概念:

      如果一个派生类从多个基类继承, 则称为多继承。

    多继承的声明:
    class 派生类名:访问控制 基类名1, 访问控制 基类名2...
    {
    成员列表
    }
    注意:
    1. 多个基类的派生类的构造函数执行的顺序与单继承的情况类似,执行顺序取决于定义派生类时指定的继承基类的顺序。

    2. 一个派生类对象拥有多个基类的成员。 不同名成员访问不会出现二义性; 如果不同的基类拥有同名成员, 派生类对象访问时应该加以识别。

    3. 如果派生类声明了一个和基类成员同名的新成员, 派生的新成员就覆盖了基类同名成员, 直接使用成员名只能访问到派生类的成员。

    #include<iostream>
    
    using namespace std;
    
    class B1
    {
    protected:
        int b1_;
    public:
        B1(int b1 = 0)
        {
            b1_ = b1;
            cout << "调用B1的构造函数" << endl;
        }
        ~B1(){}
        void print()
        {
            cout << "b1_ : " << b1_ << endl;
        }
    
        void add()
        {
            b1_ += 1;
        }
    };
    
    class B2
    {
    protected:
        int b2_;
    public:
        B2(int b2 = 0)
        {
            b2_ = b2;
            cout << "调用B2的构造函数" << endl;
        }
        ~B2(){}
        void print()
        {
            cout << "b2_ : " << b2_ << endl;
        }
    
        void add()
        {
            b2_ += 1;
        }
    };
    
    class Derived : public B1, public B2
    {
    private:
        int d_;
    public:
        //构造函数,先调用B1的,在调用B2的,最后调用Derived的
        Derived(int b1 = 0, int b2 = 0, int d = 0) : B1(b1), B2(b2)
        {
            d_ = d;
            cout << "调用Derived的构造函数" << endl;
        }
        //析构函数的调用顺序和构造函数的相反
        ~Derived(){}
    
        void print()
        {
            cout << "b1_ : " << b1_ << " b2_ : " << b2_ << " d_ : " << d_ << endl;
        }
    
    };
    
    int main()
    {
        B1 b1(5);
        b1.print();
    
        B2 b2(7);
        b2.print();
    
        Derived d1(2, 9, 4);
        Derived d2;
        //如果派生类中有和基类同名的成员,则会将基类中的成员覆盖掉
        //如果需要使用基类中的成员,则需要使用::声明
        d1.print();
        d1.B1::print();
        d1.B2::print();
    
        //如果多继承中的多个基类拥有同名的成员,访问时,应该加以识别
        d1.B1::add();
        d1.print();
    
        d1.B2::add();
        d1.print();
        return 0;
    }
    
    
    展开全文
  • C++ (多继承和虚继承)

    万次阅读 2018-07-29 16:03:13
    一个类多个基类,这样的继承关系称为多继承; b. 多继承声明语法: class 派生类名: 访问控制符 基类名1,访问控制符 基类名2 { 数据成员和成员函数声明; } class A: public B,public c { } 图示: c. 多个...

    文章概述

    1. 多继承的定义以及多继承的语法;
    2. 虚继承;

    多继承的定义以及多继承的语法

    a. 一个类有多个基类,这样的继承关系称为多继承;
    b. 多继承声明语法:

    class 派生类名: 访问控制符 基类名1,访问控制符 基类名2
    {
    数据成员和成员函数声明;
    }

    class A: public B,public c
    {
    }

    图示:
    这里写图片描述
    c. 多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序。


    虚继承

    1. 产生二义性 ?
    class A
    {
    public:
        int x;
    };
    
    class B: public A
    {
        int b;
    public:
        B(int x)
        {
            this->x = 10;
        }
    };
    
    class C : public A
    {
        int c;
    public:
        C(int x)
        {
            this->x = 20;
        }
    };
    
    class D :public B,public C
    {
        int d;
    public:
        D(int x):B(10),C(20)
        {
            //对于D中的x,到底是从哪个类(B,C)中继承的,不明确,会产生二义性。
            this->x = 30;
        }
    };

    对于产生二义性的原因分析在于分析d的对象模型:
    这里写图片描述
    其实,产生二义性的原因就在于A的构造函数在c中调用了两次,不知道x是哪个对象的。如果要让A在c中只产生一个对象,则应该对公共基类A声明为虚继承,使得这个公共基类成为虚基类。
    2. 在c中只产生一个公共基类的对象

    //当类中出现virtual时,C++编译器会对象添加一个vptr指针,同时会产生一个虚函数表
    class A
    {
    public:
        int x;  //4
    public:
        A()
        {
            cout << "A" << endl;
        }
    };
    
    class B:virtual  public A
    {
        int b; //4
    public:
        B(int x)
        {
            this->x = 10;
            cout << "B" << endl;
        }
    };
    
    class C :virtual public A
    {
        int c; //4
    public:
        C(int x)
        {
            this->x = 20;
            cout << "C" << endl;
        }
    };
    
    class D :public B,public C
    {
        int d; //4 
    public:
        D(int x):B(10),C(20)
        {
            this->x = 30;
            cout << "D" << endl;
        }
    };
    
    int main()
    {
        cout << sizeof(A) << endl;   //4
        cout << sizeof(B) << endl;   //12
        cout << sizeof(C) << endl;   //12
        cout << sizeof(D) << endl;   //24
        return 0;
    }

    分析d的对象模型:
    这里写图片描述
    C++提供虚继承机制,防止类继承关系中成员访问的二义性。

    展开全文
  • c++设计一个继承

    千次阅读 2017-08-02 12:16:42
    在Java 中定义了关键字final ,被final 修饰的继承。但在C++ 中没有final 这关键字,要实现这要求还是需要花费一些精力。 首先想到的是在C++ 中,子类的构造函数会自动调用父类的构造函数。同样,子类...

    分析:这是Adobe 公司2007 年校园招聘的最新笔试题。这道题除了考察应聘者的C++ 基本功底外,还能考察反应能力,是一道很好的题目。
    在Java 中定义了关键字final ,被final 修饰的类不能被继承。但在C++ 中没有final 这个关键字,要实现这个要求还是需要花费一些精力。
    首先想到的是在C++ 中,子类的构造函数会自动调用父类的构造函数。同样,子类的析构函数也会自动调用父类的析构函数。要想一个类不能被继承,我们只要把它的构造函数和析构函 数都定义为私有函数。那么当一个类试图从它那继承的时候,必然会由于试图调用构造函数、析构函数而导致编译错误。
    可是这个类的构造函数和析构函数都是私有函数了,我们怎样才能得到该类的实例呢?这难不倒我们,我们可以通过定义静态来创建和释放类的实例。基于这个思路,我们可以写出如下的代码:

    ///////////////////////////////////////////////////////////////////////
    // Define a class which can't be derived from
    ///////////////////////////////////////////////////////////////////////
    class FinalClass1
    {
    public :
          static FinalClass1* GetInstance()
          {
                return new FinalClass1;
          }
    
          static void DeleteInstance( FinalClass1* pInstance)
          {
                delete pInstance;
                pInstance = 0;
          }
    
    private :
          FinalClass1() {}
          ~FinalClass1() {}
    };

    这个类是不能被继承,但在总觉得它和一般的类有些不一样,使用起来也有点不方便。比如,我们只能得到位于堆上的实例,而得不到位于栈上实例。
    能不能实现一个和一般类除了不能被继承之外其他用法都一样的类呢?办法总是有的,不过需要一些技巧。请看如下代码:

    ///////////////////////////////////////////////////////////////////////
    // Define a class which can't be derived from
    ///////////////////////////////////////////////////////////////////////
    template <typename T> class MakeFinal
    {
          friend T;
    
    private :
          MakeFinal() {}
          ~MakeFinal() {}
    };
    
    class FinalClass2 : virtual public MakeFinal<FinalClass2>
    {
    public :
          FinalClass2() {}
          ~FinalClass2() {}
    };

    这个类使用起来和一般的类没有区别,可以在栈上、也可以在堆上创建实例。尽管类 MakeFinal 的构造函数和析构函数都是私有的,但由于类 FinalClass2 是它的友元函数,因此在 FinalClass2 中调用 MakeFinal 的构造函数和析构函数都不会造成编译错误。
    但当我们试图从 FinalClass2 继承一个类并创建它的实例时,却不同通过编译。

    class Try : public FinalClass2
    {
    public :
          Try() {}
          ~Try() {}
    };
    

    Try temp;
    由于类 FinalClass2 是从类 MakeFinal 虚继承过来的,在调用 Try 的构造函数的时候,会直接跳过 FinalClass2 而直接调用 MakeFinal 的构造函数。非常遗憾的是, Try 不是 MakeFinal 的友元,因此不能调用其私有的构造函数。
    基于上面的分析,试图从 FinalClass2 继承的类,一旦实例化,都会导致编译错误,因此是 FinalClass2 不能被继承。这就满足了我们设计要求。

    从另外一篇文章里面copy过来:
    如果大家熟悉java的话应该知道java中有一种类不能被继承,那就是final类.这种类有很多用处,尤其是在大的项目中控制类的继承层次. 使子类数量不至于爆炸.在使用了多继承的类层次中这也是防止出现菱形继承层次结构的一个好办法. 要实现一个不能被继承的类有很多方法.

      如何使类不能被继承呢?主要的思路就是使子类不能构造父类的部分,这样子类就没有办法实例化整个子类.这样就限制了子类的继承. 所以我们可以将父类的构造函数声明成为私有的,但是这样父类不就不能实例化了吗?可以添加一个静态帮助函数来进行构造. 虽然这样很简陋.但是这的确是一种解决方法.

      可是如果只有这个方法能够解决,那么C++实在是太不灵活了.而且这也不值得写一片文章出来!有没有办法解决上面的方法中的那些问题呢?

      当然有!我们可以利用友员不能被继承的特性!

      首先假设已经有一个类CXX.这是某一个类层次的分支,我们现在要从CXX继承一个Final子类CParent来,也就是CParent不能够被继 承. 我们可以充分利用友员不能被继承的特点,也就是说让CParent是某一个类的友员和子类,CParent可以构造,但是CParent的子类 CChild确不能继承那个友员特性,所以不能被构造.所以我们引入一个CFinalClassMixin.
    任何类从它继承都不能被实例化
    同时这个类本身我们也不希望它被实例化.
    如何实现这个类那?很简单!那就是实现一个构造函数和析构函数都是private的类就行了.同时在这类里面将我们的CParent声明为友员. 代码如下:

    class CFinalClassMixin
    {
    friend class CParent;
    private:
    CFinalClassMixin(){}
    ~CFinalClassMixin(){}
    };

    //我们的CParent代码应该如下:
    class CParent:publicCXXX
    {
    public:
    CParent(){}
    ~CParent(){}
    };

      它是从CXXX扩展的一个类(注,此时它还是能够被继承).现在我们需要它不能被继承.那么只要将代码改成

    class CParent:public CFinalClassMixin, public CXXX
    {
    public:
    CParent(){}
    ~>CParent(){}
    };

    就行了.现在从CParent继承一个子类试试

    class CChild:public CParent{};

    编译一下代码试试,发现:竟然没有作用!!

    靠,这是为什么!

      现在再回想一下我们这么操作的原因,也就是这个方案的原理,那就是让父类可以访问Mixin类的构造函数,但是子类不能访问.

      现在看看我们的代码,发现父类是CFinalClassMixin类的友员,可以访问它的构造函数.因为友员不能继承,所以CChild不能访问CFinalClassMixin的构造函数.所以应该不能被实例化.

      CChild的确不能访问CFinalClassMixin的构造函数,但是它却不必调用它!我想这就是问题的原因所在.CChild是通过CParent来构造CFinalClassMixin的,所以这个友员对他并没有什么用处!

      现在问题找到了.要解决很简单.只要让CChild必须调用CFinalClassMixin的构造函数就行了,怎么才能达到目的呢?

      还记得虚继承吗?虚继承的一个特征就是虚基类的构造函数由最终子类负责构造!所以将CParent从CFinalClassMixin继承改成从CFinalClassMixin虚继承就可以了.代码如下:

    class CParent:virtual public CFinalClassMixin, public CXXX
    {
    public:
    CParent(){}
    CParent(){}
    };
    

    现在试试,行了.

      但是可能有些人会对多继承心有余悸!但是我们这里并没有必要这么担心!为什么?因为我们的CFinalClassMixin类是纯的!pure! 也就是说它根本没有成员变量!那么我们就根本不用担心多继承带来的最大问题.菱形继承产生的数据冗余.以及二义性.

    现在还有个不足!那就是我们不能每次使用这个CFinalClassMixin类就在里面加上对某个类的友员声明啊!这多麻烦啊! 虽然不是什么大问题,但是我觉的还是要解决,因为我充分信任C++!

      解决的方法也很简单!那就是使用模板!具体描述就省略了,给出代码大家一看就知道了

    下面是我得测试程序的完整代码(其中的CFinalClassmixin已经改成模板)

    // finaltest.cpp : Defines the entry point for the console application.
    //
    #include "stdafx.h"
    #include
    using namespace std;
    
    template
    class CFinalClassMixin
    {
    friend T;
    private:
    CFinalClassMixin(){}
    ~CFinalClassMixin(){}
    };
    class CXXX
    {
    public:
    CXXX(){cout << "I am CXXX" << endl;}
    ~CXXX(){}
    };
    class CParent:virtual public CFinalClassMixin, public CXXX
    {
    public:
    CParent(){}
    ~CParent(){}
    };
    class CChild:public CParent{};
    int main(int argc, char* argv[])
    {
    CParent a; // 可以构造
    //CChild b; //不能构造
    return 0;
    }

      现在只要对不想被继承的类加入一个CFinalClassMixin混合类做父类就行了.

      通过限制构造函数,我们就达到了限制继承的目的.但是这对有些还是个例外,比如全是静态函数的类.这些类本身就不需要构造. 所以我们对它没有办法.但是在大多数情况下,一个全是静态函数的类多少暗示了程序本身的设计可能是需要斟酌的.

      其实这只是Mixin类(混合类)使用的一个小小例子.还有很多其他的用处,比如UnCopiale等等.就不多说了. 我想说明的是大家可能对多继承比较反感.但是过分否定也是得不偿失的.现在对多继承到底应不应该使用还处在争论阶段. 我觉得一个方法是否使用得当,关键还是在于使用的人.

    展开全文
  • 本文补充介绍如何从C++模板中派生出一个普通,或者说实现一个普通A,继承一个模板B。 1.实现List基类(模板) #ifndef LIST_H #define LIST_H #include using std::cout; using std::endl; enum ...
  • c++】实现一个继承

    千次阅读 2017-04-20 20:25:13
    C++如何设计一个类,是该继承?利用私有构造函数,友元和虚继承的特性来实现
  • C++类继承

    千次阅读 2018-10-21 22:18:34
    文章目录C++类继承1.is-a继承1.1公有继承1.2私有继承1.3保护继承2.has-a关系3.多态公有继承3.1特性:3.2虚函数实现原理4.纯虚函数和抽象基类5.多继承、多重继承和虚拟继承6.模板 1.is-a继承 1.1公有继承 特性: //...
  • C++多继承多重继承

    千次阅读 2019-03-09 22:32:28
    多重继承一个基类有一个派生,这个派生又有一个派生继承一个派生多个基类 下面我们看一个多重继承的例子 #include &lt;iostream&gt; #include &lt;stdlib.h&gt; #include ...
  • 多继承是指一个子类继承多个父类。多继承对父类的个数没有限制,继承方式可以是公共继承、保护继承和私有继承, 不写继承方式,默认是private继承 多继承举例: #include #include #include using ...
  • c++派生继承

    万次阅读 2017-12-23 21:04:50
    基类的构造函数和析构函数不继承,在派生中,如果对派生新增的成员进行初始化,需要加入派生的构造函数 当派生创建对象时,首先执行基类的构造函数,随后执行派生的构造函数;当撤销派生对象时,先...
  • c++继承详解

    千次阅读 多人点赞 2016-10-22 23:30:42
    继承c++语言一个重要的机制,该机制自动地为一个类提供来自另一个类的操作和数据结构,这使得程序员只需在新中定义已有的中没有的成分来建立一个。二、继承解释 继承的重要特性。A类继承B,我称B...
  • C++ (继承的基础知识)

    万次阅读 多人点赞 2018-07-29 12:53:54
    1.包含关系: A中的一个数据成员是B。 2. User关系: A部分使用B。通过之间的成员函数的相互关系。定义友元函数或者对象参数传递实现。 3. 继承关系: 具有传递性,不具有对称性。 继承的基础...
  • c++中的类继承以及初始化顺序

    千次阅读 2013-12-11 20:59:38
    对于以及类继承, 几主要的问题: 1) 继承方式: public/protected/private继承. 这是c++搞的, 实际上继承方式是种允许子类控制的思想. 子类通过public继承, 可以把基类真实还原, 而private继承则完全把基类...
  • C++中禁止继承的方法

    千次阅读 2013-03-07 12:03:43
    [转]C++中禁止继承的方法 ...要防止一个类继承,我们的目标就是如果这个继承,那么编译的时候就会出错,要是现这个目标,我们必须利用语言的一些特性,使得继承在编译时 C++需要为
  • 关于c++多继承(有关接口)

    千次阅读 2013-12-27 23:11:28
    大家在学java C#的时候一定会看到类似这样的话“一些语言如C++支持所谓的‘多重继承’,即一个类派生于多个。使用多重继承优点是有争议的:一方面,可以使用多重继承编写非常复杂、但很紧凑的代码;另一方面,...
  • C++继承和重载

    千次阅读 多人点赞 2019-04-12 19:49:37
    C++继承和重载 c++集成 继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。...一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生,我们使用一个...
  • c++模板继承中子无法访问父类的成员

    千次阅读 多人点赞 2018-03-23 17:58:01
    c++模板继承中子无法访问父类的成员 问题:c++模板继承中子无法访问父类的成员 解决方法:在子类访问父类时加上父类的前缀或使用this-&gt;调用 c++从入门到放弃,感觉c++了解的越,就越...
  • C/C++类继承

    万次阅读 2019-02-14 12:17:21
    .继承 class Shape{ }; class Circle : public Shape{ }; 语法:class B : public A{} B继承于A,A是父类,B是派生(子类) 当 B继承于A时,自动将父类中的所有public 成员继承,无法继承private的...
  • 详细讲解C++ 继承

    万次阅读 2008-01-23 09:16:00
    一个私有的或保护的派生不是子类,因为非公共的派生做基类做的所有的事,就是指在公开场合,但是在内部可以的一、引言在C++中,是提供封装的逻辑单位,的每一个对象都包含有描述其自身状态的数据...
1 2 3 4 5 ... 20
收藏数 233,397
精华内容 93,358
关键字:

c++一个类能继承多个类吗