C++多重继承和虚基类的学习

文章讨论了C++中的多重继承概念,通过示例展示了当子类从具有共同基类的多个类继承时可能出现的二义性问题。为了解决这个问题,文章介绍了虚基类的概念,虚基类确保即使在多重继承的情况下,也只会有一个基类对象。文章还提供了使用虚基类的代码示例,演示了如何避免二义性并正确构造对象。
摘要由CSDN通过智能技术生成

多重继承

多重继承是指一个类继承了多个基类。例如:

class ClassCadres : public Student , public Worker
{
    ...
};

ClassCadres同时继承了Student类和Worker类,ClassCadres同时拥有了StudentWorker的属性。

多重继承的问题

祖先相同的多重继承。

例如:StudentWorker都继承自Person类,而ClassCadres同时继承了StudentWorker类。

在这里插入图片描述

这样会产生两个问题:

  • 从两个不同的基类继承了同名方法;
  • 产生多个祖先类对象。

实例一

Person.h

#ifndef PERSON_H_
#define PERSON_H_
#include <string>
#include <iostream>
class Person
{
    private:
        std::string m_name;
        int m_age;
    public:
        Person()
            : m_name("no name"), m_age(15) { std::cout << "constructor\n"; }
        Person(const char *name, int age)
            : m_name(name), m_age(age) {}
        virtual ~Person() = 0;      // 纯虚析构函数
        virtual void HShow() const;     // 虚函数
};

class Student : public Person
{
    private:
        std::string m_sex;
    public:
        Student()
            : Person(), m_sex("female") {}
        Student(const char *name, int age, const char *sex)
            : Person(name, age), m_sex(sex) {}
        Student(const Person &p, const char *sex)
            : Person(p), m_sex(sex) {}
        virtual void HShow() const;
};

class Worker : public Person
{
    private:
        std::string m_job;
    public:
        Worker()
            : Person(),m_job("none") {}
        Worker(const char *name, int age, const char *job)
            : Person(name, age), m_job(job) {}
        Worker(const Person &p, const char *job)
            : Person(p), m_job(job) {}
        virtual void HShow() const;
};

// 多重继承
class ClassCadres : public Student , public Worker  
{
    public:
        ClassCadres()
            : Student(), Worker() {}
        ClassCadres(const char *name, int age, const char *sex, const char *job)
            : Student(name, age, sex), Worker(name, age, job) {}
};


#endif

Person.cpp

#include "Person.h"
Person::~Person()
{

}
void Person::HShow() const
{
    std::cout << "Name: " << m_name << std::endl;
}

void Student::HShow() const
{
    Person::HShow();
    std::cout << "Sex: " << m_sex << std::endl;
}

void Worker::HShow() const
{
    Person::HShow();
    std::cout << "Job: " << m_job << std::endl;   
}

main.cpp

#include "Person.h"
#include <iostream>
using std::endl;
using std::cout;

int main()
{
    ClassCadres c1;
    // c1.HShow();     // 产生二义性
    c1.Worker::HShow(); 
    c1.Student::HShow();

    // Person *p1 = &c1;   // 二义性
    Person *p1 = (Student *)&c1;
    Person *p2 = (Worker *)&c1;
    return 0;
}

程序说明

  1. 运行程序打印了两次"constructor",说明产生了两个Person类对象。
  2. 如果c1直接使用HShow()方法,将会产生二义性,所以需要指明是哪个对象的方法。
  3. 如果将将派生类对象地址赋给基类指针,也将产生二义性,所以需要指明转为哪个对象。

使用虚基类可以解决多重继承带来的问题。

虚基类

虚基类使得从多个类(它们的基类相同)派生出的对象只继承一个基类对象。

通过在类声明中使用关键字virtual,可以使Person类作为StudentWorker的虚基类:

class Student : virtual public Person { ... };
class Worker : public virtual Person { ... };   // virtual和public顺序无关紧要
class ClassCadres : public Student, public Worker 
{ 
    ... 
};  // ClassCadres将只包含一个Person对象

在这里插入图片描述

实例二

Person.h

#ifndef PERSON_H_
#define PERSON_H_
#include <string>
#include <iostream>
class Person
{
    private:
        std::string m_name;
        int m_age;
    protected:
        virtual void HData() const;
    public:
        Person()
            : m_name("no name"), m_age(15) { std::cout << "constructor\n"; }
        Person(const char *name, int age)
            : m_name(name), m_age(age) {}
        virtual ~Person() {};   //  虚析构函数
        virtual void HShow() const;   // 虚函数
};

class Student : virtual public Person
{
    private:
        std::string m_sex;
    protected:
        virtual void HData() const;
    public:
        Student()
            : Person(), m_sex("female") {}
        Student(const char *name, int age, const char *sex)
            : Person(name, age), m_sex(sex) {}
        Student(const Person &p, const char *sex)
            : Person(p), m_sex(sex) {}
        virtual void HShow() const;
};

class Worker : public virtual Person
{
    private:
        std::string m_job;
    protected:
        virtual void HData() const;
    public:
        Worker()
            : Person(),m_job("none") {}
        Worker(const char *name, int age, const char *job)
            : Person(name, age), m_job(job) {}
        Worker(const Person &p, const char *job)
            : Person(p), m_job(job) {}
        virtual void HShow() const;
};

// 多重继承
class ClassCadres : public Student , public Worker  
{
    protected:
        virtual void HData() const;
    public:
        ClassCadres() {}
        ClassCadres(const char *name, int age, const char *sex, const char *job)
            : Person(name, age), Student(name, age, sex), Worker(name, age, job) {}
        ClassCadres(const Person &p, const char *sex, const char *job)
            : Person(p), Student(p, sex), Worker(p, job) {}
        ClassCadres(const Student &stu, const char *job)
            : Person(stu), Student(stu), Worker(stu,job) {}
        ClassCadres(const Worker &w, const char *sex)
            : Person(w), Student(w, sex), Worker(w) {}
        virtual void HShow() const;
};


#endif

Person.cpp

#include "Person.h"
void Person::HData() const
{
    std::cout << "Name: " << m_name << std::endl;
}

void Person::HShow() const
{
    HData();
}

void Student::HData() const
{
    std::cout << "Sex: " << m_sex << std::endl;
}
void Student::HShow() const
{
    Person::HData();
    HData();
}

void Worker::HData() const
{
    std::cout << "Job: " << m_job << std::endl;
}
void Worker::HShow() const
{
    Person::HData();
    HData();
}

void ClassCadres::HData() const
{
    Student::HData();
    Worker::HData();
}
void ClassCadres::HShow() const
{
    Person::HData();
    HData();   
}

main.cpp

#include "Person.h"
#include <iostream>
using std::endl;
using std::cout;

int main()
{
    ClassCadres c1;
    c1.HShow();
    cout << endl;

    Student stu1("zhangsan", 18, "nan");
    stu1.HShow();
    cout << endl;
    
    ClassCadres c2(stu1, "Representative");
    c2.HShow();
    cout << endl;

    Worker w1("lisi", 19, "Monitor");
    w1.HShow();
    cout << endl;


    ClassCadres c3(w1, "Female");
    c3.HShow();
    cout << endl;

    Person p1("wangwu", 18);
    p1.HShow();
    cout << endl;
    ClassCadres c4(p1, "Man", "Monitor");
    c4.HShow();
    return 0;
}

程序说明

  1. 从打印结果可知,"constructor"只打印了一次,说明只有一个基类对象。
  2. 新的构造规则:
ClassCadres(const Person &p, const char *sex, const char *job)
    : Person(p), Student(p, sex), Worker(p, job) {}

上述代码将显示调用祖先的构造函数Person(const Person &),这种用法是合法的,对于虚基类必须这样做;但对于非虚基类,则是非法的。

如果不显示调用祖先的构造函数,将会调用Person类的默认构造函数

ClassCadres(const Person &p, const char *sex, const char *job)
    : Student(p, sex), Worker(p, job) {}

注意:如果类有间接虚基类,则除非只需使用该虚基类的默认构造函数,否则必须显示地调用该虚基类的某个构造函数。

  1. 其中定义了一个保护成员HData(),用来打印本类特有的属性。只可以在类内部使用,作为公有接口的辅助方法。
  2. 使用作用域解析运算符来区分类方法
Person::HData();
Student::HData();
Worker::HData();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值