C ++ (inheritance): 18 --- multiple inheritance

First, the concept of multiple inheritance

  • Multiple inheritance means: from a plurality of direct base classes and the ability to produce a derived class
  • E.g:
class ZooAnimal {}; //动物

class Endangered {}; //濒临灭绝的动物

class Bear :public ZooAnimal {};  //熊

//多重继承
class Panda :public Bear, public Endangered {}; //熊猫

Second, multiple inheritance syntax

  • Each group must have a class that inherits optional access specifier (public, protected, private). If not: for class, it defaults to private, for struct defaults to public speaking
  • Inherited base class must be defined in a declaration before the class definitions
  • Inherited base class can not make the final of the (final see: https://blog.csdn.net/qq_41453285/article/details/103105885 )
  • The number of base class can inherit is not limited, but the same base class can inherit only once

Third, the initialization sequence constructor

  • Construction order as the base class derivation list appears related to the base class, regardless of the initialization sequence constructor initializes the list of base classes
  • Also you need to construct the base class object before the derived class constructor yourself. E.g:
class Panda :public Bear, public Endangered {
public:
    //构造所有基类
    Panda(std::string name, bool onExhibit)
        :Bear(name, onExhibit, "Panda"),
         Endangered(Endangered::cirtical)
    {
    }

    //使用Bear的默认构造函数初始化Bear对象
    Panda::Panda()
        : Endangered(Endangered::cirtical)
    {
    }
};
  • Panda constructor for the above, execution order is: ZooAnimal-> Bear-> Endangered-> Panda

Fourth, the destructor

  • Destructor derived class needs to perform the same function in the base class fiction
  • The execution sequence and inheritance opposite destructor
  • For the above Panda destructor, execution order is: Panda-> Endangered-> Bear-> ZooAnimal

Fifth, the inherited constructor with multiple inheritance

  • "Inherited constructor" We introduced over previous article: https://blog.csdn.net/qq_41453285/article/details/104435826
  • Inherited constructor uses the concept of using a constructor inherited from the base class
  • In C ++ 11 standard, the constructor allows a derived class inherits from one or more of its base class. However, if the same constructor inherited from a base class in the plurality of (the same is identical, the argument list), the program will generate an error

Case presentation

struct Base1 {
    Base1() = default;
    Base1(const std::string&);
    Base1(std::shared_ptr<int>);
};

struct Base2 {
    Base2() = default;
    Base2(const std::string&);
    Base2(int);
};

//多重继承
struct D1 :public Base1, public Base2 {
    //使用using继承基类中的构造函数
    using Base1::Base1;
    using Base2::Base2; //会产生错误
};
  • D1 above Base1 and Base2 are inherited from all constructors, but Base1 and Base2 in both a parameter "const std :: string &" constructor, the compiler generates an error

  • To solve the above error, you must own explicitly defined in this class may produce ambiguous constructor, this approach is what we call coverage. See the following demo case

Case presentation

struct Base1 {
    Base1() = default;
    Base1(const std::string&);
    Base1(std::shared_ptr<int>);
};

struct Base2 {
    Base2() = default;
    Base2(const std::string&);
    Base2(int);
};

struct D1 :public Base1, public Base2 {
    using Base1::Base1;
    using Base2::Base2;
    
    //覆盖两个基类的const std::string&参数构造函数版本
    D1(const std::string &s):Base1(s), Base2(s){}
    D1() = default; //一旦定义了自己的构造函数,则必须出现
};

Sixth, multiple copies of a derived class that inherits the moving operation

The use of non-synthetic version

  • Consistent with the principle of single inheritance, multiple inheritance if the derived class defines its own copy / assignment constructor and assignment operator, you must perform a copy, move, assignment on the complete object (that is recommended to copy, move , partial data belonging to the assignment group and the like)

Synthetic version

  • If the derived class does not define its own copy / assignment constructor and assignment operator, it will automatically call the base class copy / assignment constructor and assignment operator in performing these operations

Seven types of base class and the derived class conversion

  • Consistent with the principle of single inheritance, a derived class can be assigned to a base class can also be a base class pointer / reference point in a derived class
  • E.g:
class ZooAnimal {};

class Endangered {};

class Bear :public ZooAnimal {};

class Panda :public Bear, public Endangered {};

void print(const Bear&);
void highlight(const Endangered&);
ostream& operator<<(ostream&, const ZooAnimal&);

int main()
{
    Panda ying_yang("ying_yang");

    print(ying_yang);         //将一个Panda对象传递给一个Bear引用
    highlight(ying_yang);     //将一个Panda对象传递给一个Endangered引用
    cout << ying_yang << endl;//将一个Panda对象传递给一个ZooAnimal引用
	
    return 0;
}

Note ambiguous function overloading and errors

  • The compiler does not compare and choose to convert the base class in a derived class, because it seems to switch to any of the base classes are the same. Note, however ambiguous questions:
class ZooAnimal {};

class Endangered {};

class Bear :public ZooAnimal {};

class Panda :public Bear, public Endangered {};

void print(const Bear&);
void print(const Endangered&);

int main()
{
    Panda ying_yang("ying_yang");
    print(ying_yang);//产生二义性
	
    return 0;
}

Based on the type of pointer or reference type lookup

  • Consistent with the principle of single inheritance, object, reference, pointer static type determines which members can use us
  • E.g:
    • We use a pointer to ZooAnimal in a derived class, then this can only be accessed through a pointer data members belong ZooAnimal / methods, but can not call data belonging to members of the base class / method
    • We use a Bear pointer to the object in Panda, you can only access through this pointer as well as members belonging to Bear ZooAnimal can not access the data members of the Panda / methods and data members Endangered / methods

Case presentation:

class ZooAnimal {
public:
    virtual void print();  //1
    virtual ~ZooAnimal();
};

class Endangered {
public:
    virtual void print();     //1
    virtual void highlight(); //2
    virtual ~Endangered();
};

class Bear :public ZooAnimal {
public:
    virtual void print();  //1
    virtual void toes();   //3
};

class Panda :public Bear, public Endangered {
public:
    virtual void print();     //1
    virtual void highlight(); //2
    virtual void toes();      //3
    virtual void cuddle();    //4
};
  • Now we have the following call:

int main()
{
    Bear *pb = new Panda("ying_yang");
    
    pb->print();     //正确,调用Panda::print()
    pb->cuddle();    //错误,不属于Bear接口
    pb->highlight(); //错误,不属于Bear接口
    
    delete pb;       //正确,调用Panda::~Panda()
    
    return 0;
}
  • Now we have the following call:
int main()
{
    Endangered *pb = new Panda("ying_yang");

    pb->print();    //正确,调用Panda::print()
    pb->toes();     //错误,不属于Endangered的接口
    pb->cuddle();   //错误,不属于Endangered的接口
    pb->highlight();//正确,调用Panda::highlight

    delete pb;      //正确,调用Panda::~Panda()

    return 0;
}

Eight class scope under multiple inheritance

  • In single inheritance we have said, the derived class's scope is nested in the base class action directly or indirectly to the base class field, which means that when we look for a data member / method, does not exist in a derived class, then Find proceed to the base class, if you were using to find
  • Multiple inheritance of the derived class in the role of all the nested scopes base or indirect base class domain

Ambiguity and ambiguity of the two settlements

  • When the same data member names / functions appear in different base classes, program error (compiler allows definition) does not occur. But if we make a call to the data members of the same name / functions through the derived class, it will trigger ambiguity
class A {
public:
    int num;
};

class B {
public:
    int num;
};

//允许多重继承
class C :public A, public B {};

int main()
{
    C c;
    c.num;   //错误,对num地调用产生二义性
    return 0;
}
  • If the derived class data members may produce ambiguous / functions covered, then the call will not produce the ambiguity. E.g:
class A {
public:
    int num;
};

class B {
public:
    int num;
};

class C :public A, public B {
public:
    int num; //覆盖
};

int main()
{
    C c;
    c.num; //正确
    return 0;
}
  • Of course, we can without coverage, scope qualifier accessed by calling members of which version of the data / methods
class A {
public:
    int num;
};

class B {
public:
    int num;
};

class C :public A, public B {};

int main()
{
    C c;
    c.A::num; //调用A中的num
    c.B::num; //调用B中的num
    return 0;
}
  • Of course, we can also design a function to access a particular version with access
class A {
protected:
    int num; //不能是private的,否则派生类不可访问
};

class B {
protected:
    int num; //不能是private的,否则派生类不可访问
};

class C :public A, public B {
    int max_numconst()const{
        return std::max(A::num, B::num);
    }
};
  • Precautions:
    • Sometimes, even if derived class inherits function formal parameter list two different error may also occur
    • Further, the data members of the same name / function in different base class can access different error may occur (e.g., a private data member in a base class, the base class is protected in the 2, error also occurs )
Released 1481 original articles · won praise 1026 · Views 380,000 +

Guess you like

Origin blog.csdn.net/qq_41453285/article/details/104440557