C++多继承与虚基类详解 含实例

在这里插入图片描述
虚基类版本:

#include<iostream>
#include<time.h>
#include<math.h>
#include<string.h>
using namespace std;

class Birthday {
    
    
public:
    Birthday() {
    
    }
    Birthday(int year, int month, int day) {
    
    
        year_ = year;
        month_ = month;
        day_ = day;
    }
    void print() {
    
    
        cout << "year:\t" << year_ << endl;
        cout << "month\t" << month_ << endl;
        cout << "day:\t" << day_ << endl;
    }
private:
    int day_;
    int month_;
    int year_;
};

enum Gender_ {
    
    
    Male,
    Female
};

class Person
{
    
    
public:
    Person() {
    
    }
    Person(string name, Gender_ gender, Birthday birth) {
    
    
        name_ = name;
        gender_ = gender;
        birth_ = birth;
    }
    ~Person() {
    
    }
    void Print() {
    
    
        birth_.print();
        cout << "name is:\t" << name_ << endl;
        string genderString;
        if (gender_ == 0)
            genderString = "Male";
        else
            genderString = "Female";
        cout << "gender is:\t" << genderString << endl;
    }

    void Address() {
    
    
        cout << this << endl;
    }

protected:
    string name_;
    Gender_ gender_;
    Birthday birth_;
};

class Student : virtual public Person {
    
    

public:
    Student() {
    
    }
    Student(string name, Gender_ gender, Birthday birth, int score) :Person(name, gender, birth) {
    
    
        score_ = score;
    }
    ~Student() {
    
    }
    void Print() {
    
    
        Person::Print();
        cout << "score is:\t" << score_ << endl;
    }

protected:
    int score_;
};

class Graduate : public Student {
    
    

public:
    Graduate() {
    
    }
    Graduate(string name, Gender_ gender, Birthday birth, int score, string advisor) :Person(name, gender, birth)/*虚基类所有直接与间接的派生类都必须在初始化列表中调用虚基类的构造函数*/, Student(name, gender, birth, score) {
    
    
        advisor_ = advisor;
    }
    ~Graduate() {
    
    }
    void Print() {
    
    
        Student::Print();
        cout << "advisor is:\t" << advisor_ << endl;
    }
    void PrintAdvisor() {
    
    
        cout << "advisor is:\t" << advisor_ << endl;
    }

protected:
    string advisor_;
};

class Teacher :virtual public Person {
    
    
public:
    Teacher() {
    
    }
    Teacher(string name, Gender_ gender, Birthday birth, string title) :Person(name, gender, birth) {
    
    
        title_ = title;
    }
    void Print() {
    
    
        Person::Print();
        cout << "title is:\t" << title_ << endl;
    }
    void PrintTitle() {
    
    
        cout << "title is:\t" << title_ << endl;
    }
protected:
    string title_;
};

class Assistant :public Graduate, public Teacher {
    
    
public:
    Assistant() {
    
    }
    Assistant(string name, Gender_ gender, Birthday birth, int score, string advisor, string title, string subject) :Person(name, gender, birth), Graduate(name, gender, birth, score, advisor), Teacher(name, gender, birth, title) {
    
    
        subject_ = subject;
    }
    void Print() {
    
    
        /*Graduate::Print();
        cout << "---\n";
        Teacher::Print();*/

        /*cout << "name is:" << Person::name_ << endl;
         cout << "gender is:" << Person::gender_ << endl;
         Person::birth_.print();
         cout << "score is:" << Student::score_ << endl;*/
        Student::Print();
        cout << "advisor is:\t" << Graduate::advisor_ << endl;
        cout << "title is:\t" << Teacher::title_ << endl;
        cout << "subjet is:\t" << subject_ << endl;


    }
    void PrintSubject() {
    
    
        cout << "subject is:\t" << subject_ << endl;
    }
protected:
    string subject_;
};

int main() {
    
    
    Birthday birthPerson(1000, 1, 1);
    Person person("Spinoza", Male, birthPerson);
    Birthday birthStudent(2021, 10, 28);
    Student student("Descartes", Male, birthStudent, 100);
    Birthday birthTeacher(1990, 10, 28);
    Teacher teacher("Leibniz", Male, birthTeacher, "Teaching Affairs");
    Birthday birthgraduate(2000, 2, 2);
    Graduate graduate("graduate", Male, birthgraduate, 99, "Teaching Affairs");
    Birthday birthassitant(1998, 8, 8);
    Assistant assitant("assitant", Male, birthassitant, 99, "advisor", "title", "subject");

    cout << "-------person------------\n";
    person.Print();
    cout << "-------student------------\n";
    student.Print();
    cout << "-------teacher------------\n";
    teacher.Print();
    cout << "-------Graduate------------\n";
    graduate.Print();
    //graduate.PrintAdvisor();
    cout << "-------Assitant------------\n";
    assitant.Print();
    //assitant.PrintSubject();

    Assistant test;
    Graduate* a = &test;
    Teacher* b = &test;
    Student* c = &test;
    Person* d = &test;
    Person* a1 = a;
    Person* a2 = b;
    Person* a3 = c;
    cout << a << "\n" << b << "\n" << c << "\n" << d << "\n" << a1 << "\n" << a2 << "\n" << a3 << "\n----------------" << endl;

    person.Address();
    student.Address();
    graduate.Address();
    teacher.Address();
    assitant.Address();

    return 0;

}

非虚基类:
发现有歧义部分的都报错了,比如不知道通过哪个途径向上转型。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
可以看到向上转型,基类指针指向的是同一个对象。

#include<iostream>
#include<time.h>
#include<math.h>
#include<string.h>
using namespace std;

class Birthday {
    
    
public:
    Birthday() {
    
    }
    Birthday(int year, int month, int day) {
    
    
        year_ = year;
        month_ = month;
        day_ = day;
    }
    void print() {
    
    
        cout << "year:\t" << year_ << endl;
        cout << "month\t" << month_ << endl;
        cout << "day:\t" << day_ << endl;
    }
private:
    int day_;
    int month_;
    int year_;
};

enum Gender_ {
    
    
    Male,
    Female
};

class Person
{
    
    
public:
    Person() {
    
    }
    Person(string name, Gender_ gender, Birthday birth) {
    
    
        name_ = name;
        gender_ = gender;
        birth_ = birth;
    }
    ~Person() {
    
    }
    void Print() {
    
    
        birth_.print();
        cout << "name is:\t" << name_ << endl;
        string genderString;
        if (gender_ == 0)
            genderString = "Male";
        else
            genderString = "Female";
        cout << "gender is:\t" << genderString << endl;
    }

    void Address() {
    
    
        cout << this << endl;
    }

protected:
    string name_;
    Gender_ gender_;
    Birthday birth_;
};

class Student : public Person {
    
    

public:
    Student() {
    
    }
    Student(string name, Gender_ gender, Birthday birth, int score) :Person(name, gender, birth) {
    
    
        score_ = score;
    }
    ~Student() {
    
    }
    void Print() {
    
    
        Person::Print();
        cout << "score is:\t" << score_ << endl;
    }

protected:
    int score_;
};

class Graduate : public Student {
    
    

public:
    Graduate() {
    
    }
    Graduate(string name, Gender_ gender, Birthday birth, int score, string advisor) : Student(name, gender, birth, score) {
    
    
        advisor_ = advisor;
    }
    ~Graduate() {
    
    }
    void Print() {
    
    
        Student::Print();
        cout << "advisor is:\t" << advisor_ << endl;
    }
    void PrintAdvisor() {
    
    
        cout << "advisor is:\t" << advisor_ << endl;
    }

protected:
    string advisor_;
};

class Teacher :public Person {
    
    
public:
    Teacher() {
    
    }
    Teacher(string name, Gender_ gender, Birthday birth, string title) :Person(name, gender, birth) {
    
    
        title_ = title;
    }
    void Print() {
    
    
        Person::Print();
        cout << "title is:\t" << title_ << endl;
    }
    void PrintTitle() {
    
    
        cout << "title is:\t" << title_ << endl;
    }
protected:
    string title_;
};

class Assistant :public Graduate, public Teacher {
    
    
public:
    Assistant() {
    
    }
    Assistant(string name, Gender_ gender, Birthday birth, int score, string advisor, string title, string subject) :Person(name, gender, birth), Graduate(name, gender, birth, score, advisor), Teacher(name, gender, birth, title) {
    
    
        subject_ = subject;
    }
    void Print() {
    
    
        /*Graduate::Print();
        cout << "---\n";
        Teacher::Print();*/

        /*cout << "name is:" << Person::name_ << endl;
         cout << "gender is:" << Person::gender_ << endl;
         Person::birth_.print();
         cout << "score is:" << Student::score_ << endl;*/
        Student::Print();
        cout << "advisor is:\t" << Graduate::advisor_ << endl;
        cout << "title is:\t" << Teacher::title_ << endl;
        cout << "subjet is:\t" << subject_ << endl;


    }
    void PrintSubject() {
    
    
        cout << "subject is:\t" << subject_ << endl;
    }
protected:
    string subject_;
};

int main() {
    
    
    Birthday birthPerson(1000, 1, 1);
    Person person("Spinoza", Male, birthPerson);
    Birthday birthStudent(2021, 10, 28);
    Student student("Descartes", Male, birthStudent, 100);
    Birthday birthTeacher(1990, 10, 28);
    Teacher teacher("Leibniz", Male, birthTeacher, "Teaching Affairs");
    Birthday birthgraduate(2000, 2, 2);
    Graduate graduate("graduate", Male, birthgraduate, 99, "Teaching Affairs");
    Birthday birthassitant(1998, 8, 8);
    Assistant assitant("assitant", Male, birthassitant, 99, "advisor", "title", "subject");

    cout << "-------person------------\n";
    person.Print();
    cout << "-------student------------\n";
    student.Print();
    cout << "-------teacher------------\n";
    teacher.Print();
    cout << "-------Graduate------------\n";
    graduate.Print();
    //graduate.PrintAdvisor();
    cout << "-------Assitant------------\n";
    assitant.Print();
    //assitant.PrintSubject();

    Assistant test;
    Graduate* a = &test;
    Teacher* b = &test;
    Student* c = &test;
    //Person* d = &test;
    Person* a1 = a;
    Person* a2 = b;
    Person* a3 = c;
    cout << a << "\n" << b << "\n" << c << "\n" /*<< d */<< "\n" << a1 << "\n" << a2 << "\n" << a3 << "\n----------------" << endl;

    person.Address();
    student.Address();
    graduate.Address();
    teacher.Address();
    //assitant.Address();

    return 0;

}

在这里插入图片描述
可以看到向上转型,不同继承路线上的基类指针指向的是不同对象。
具体为什么person-student-graduate路线上的指针指向的是同一个对象,我们继续验证。

在这里插入图片描述
进一步验证

#include<iostream>
#include<time.h>
#include<math.h>
#include<string.h>
using namespace std;

class Birthday {
    
    
public:
    Birthday() {
    
    }
    Birthday(int year, int month, int day) {
    
    
        year_ = year;
        month_ = month;
        day_ = day;
    }
    void print() {
    
    
        cout << "year:\t" << year_ << endl;
        cout << "month\t" << month_ << endl;
        cout << "day:\t" << day_ << endl;
    }
private:
    int day_;
    int month_;
    int year_;
};

enum Gender_ {
    
    
    Male,
    Female
};

class Person
{
    
    
public:
    Person() {
    
    }
    Person(string name, Gender_ gender, Birthday birth) {
    
    
        name_ = name;
        gender_ = gender;
        birth_ = birth;
    }
    ~Person() {
    
    }
    void Print() {
    
    
        birth_.print();
        cout << "name is:\t" << name_ << endl;
        string genderString;
        if (gender_ == 0)
            genderString = "Male";
        else
            genderString = "Female";
        cout << "gender is:\t" << genderString << endl;
    }
    
    void Address() {
    
    
        cout << this << endl;
    }


    string name_;
    Gender_ gender_;
    Birthday birth_;
};

class Student : public Person {
    
    

public:
    Student() {
    
    }
    Student(string name, Gender_ gender, Birthday birth, int score) :Person(name, gender, birth) {
    
    
        score_ = score;
    }
    ~Student() {
    
    }
    void Print() {
    
    
        Person::Print();
        cout << "score is:\t" << score_ << endl;
    }

    int score_;
};

class Graduate : public Student {
    
    

public:
    Graduate() {
    
    }
    Graduate(string name, Gender_ gender, Birthday birth, int score, string advisor) : /*Person(name, gender, birth), */ Student(name, gender, birth, score) {
    
    
        advisor_ = advisor;
    }
    ~Graduate() {
    
    }
    void Print() {
    
    
        Student::Print();
        cout << "advisor is:\t" << advisor_ << endl;
    }
    void PrintAdvisor() {
    
    
        cout << "advisor is:\t" << advisor_ << endl;
    }


    string advisor_;
};

class Teacher :public Person {
    
    
public:
    Teacher() {
    
    }
    Teacher(string name, Gender_ gender, Birthday birth, string title) :Person(name, gender, birth) {
    
    
        title_ = title;
    }
    void Print() {
    
    
        Person::Print();
        cout << "title is:\t" << title_ << endl;
    }
    void PrintTitle() {
    
    
        cout << "title is:\t" << title_ << endl;
    }

    string title_;
};

class Assistant :public Graduate, public Teacher {
    
    
public:
    Assistant() {
    
    }
    Assistant(string name, Gender_ gender, Birthday birth, int score, string advisor, string title, string subject) :/*Person(name, gender, birth),*/ Graduate(name, gender, birth, score, advisor), Teacher(name, gender, birth, title) {
    
    
        subject_ = subject;
    }
    void Print() {
    
    
        /*Graduate::Print();
        cout << "---\n";
        Teacher::Print();*/

        /*cout << "name is:" << Person::name_ << endl;
         cout << "gender is:" << Person::gender_ << endl;
         Person::birth_.print();
         cout << "score is:" << Student::score_ << endl;*/
        Student::Print();
        cout << "advisor is:\t" << Graduate::advisor_ << endl;
        cout << "title is:\t" << Teacher::title_ << endl;
        cout << "subjet is:\t" << subject_ << endl;

    }
    void PrintSubject() {
    
    
        cout << "subject is:\t" << subject_ << endl;
    }

    string subject_;
};

int main() {
    
    
    Birthday birthPerson(1000, 1, 1);
    Person person("Spinoza", Male, birthPerson);
    Birthday birthStudent(2021, 10, 28);
    Student student("Descartes", Male, birthStudent, 100);
    Birthday birthTeacher(1990, 10, 28);
    Teacher teacher("Leibniz", Male, birthTeacher, "Teaching Affairs");
    Birthday birthgraduate(2000, 2, 2);
    Graduate graduate("graduate", Male, birthgraduate, 99, "Teaching Affairs");
    Birthday birthassitant(1998, 8, 8);
    Assistant assitant("assitant", Male, birthassitant, 99, "advisor", "title", "subject");

    cout << "-------person------------\n";
    person.Print();
    cout << "-------student------------\n";
    student.Print();
    cout << "-------teacher------------\n";
    teacher.Print();
    cout << "-------Graduate------------\n";
    graduate.Print();
    //graduate.PrintAdvisor();
    cout << "-------Assitant------------\n";
    assitant.Print();
    //assitant.PrintSubject();

    Assistant test;
    Graduate* a = &test;
    Teacher* b = &test;
    Student* c = &test;
    //Person* d = &test;
    Person* a1 = a;
    Person* a2 = b;
    Person* a3 = c;
    cout << a << "\n" << b << "\n" << c << "\n" /*<< d */<< "\n" << a1 << "\n" << a2 << "\n" << a3 << "\n----------------" << endl;
    
    person.Address();
    student.Address();
    graduate.Address();
    teacher.Address();
    cout << "assitantAddress: " << endl;
    assitant.Teacher::Address();
    assitant.Person::Address();
    assitant.Student::Address();
    assitant.Graduate::Address();
    
    assitant.Person::name_ = "np";
    assitant.Graduate::name_ = "nG";
    assitant.Student::name_ = "nS";
    assitant.Teacher::name_ = "nT";

    cout << assitant.Person::name_ << "\n" << assitant.Graduate::name_ << "\n" << assitant.Student::name_ << "\n" << assitant.Teacher::name_ << endl;

    return 0;

}

发现无论如何排列给name赋值的语句,teacher始终打印nT,另外三个始终打印最后赋值的那个。可以看出对象有两块内存区域,分别存储两条继承线路上的值。所以我们多用了一块内存。浪费了空间,造成了歧义。
在这里插入图片描述
进一步验证:
加上虚基类:
在这里插入图片描述
这两个方法不再报错了。
向上转型,有虚基类的情况下,所有基类指针还是均指向同一对象。
并且所有成员变量只有一块内存(即此处nT是最后一次赋上的值),所以我们节省了一块内存。
在这里插入图片描述
代码如下:

#include<iostream>
#include<time.h>
#include<math.h>
#include<string.h>
using namespace std;

class Birthday {
    
    
public:
    Birthday() {
    
    }
    Birthday(int year, int month, int day) {
    
    
        year_ = year;
        month_ = month;
        day_ = day;
    }
    void print() {
    
    
        cout << "year:\t" << year_ << endl;
        cout << "month\t" << month_ << endl;
        cout << "day:\t" << day_ << endl;
    }
private:
    int day_;
    int month_;
    int year_;
};

enum Gender_ {
    
    
    Male,
    Female
};

class Person
{
    
    
public:
    Person() {
    
    }
    Person(string name, Gender_ gender, Birthday birth) {
    
    
        name_ = name;
        gender_ = gender;
        birth_ = birth;
    }
    ~Person() {
    
    }
    void Print() {
    
    
        birth_.print();
        cout << "name is:\t" << name_ << endl;
        string genderString;
        if (gender_ == 0)
            genderString = "Male";
        else
            genderString = "Female";
        cout << "gender is:\t" << genderString << endl;
    }

    void Address() {
    
    
        cout << this << endl;
    }


    string name_;
    Gender_ gender_;
    Birthday birth_;
};

class Student : virtual public Person {
    
    

public:
    Student() {
    
    }
    Student(string name, Gender_ gender, Birthday birth, int score) :Person(name, gender, birth) {
    
    
        score_ = score;
    }
    ~Student() {
    
    }
    void Print() {
    
    
        Person::Print();
        cout << "score is:\t" << score_ << endl;
    }


    int score_;
};

class Graduate : public Student {
    
    

public:
    Graduate() {
    
    }
    Graduate(string name, Gender_ gender, Birthday birth, int score, string advisor) :Person(name, gender, birth)/*虚基类所有直接与间接的派生类都必须在初始化列表中调用虚基类的构造函数*/, Student(name, gender, birth, score) {
    
    
        advisor_ = advisor;
    }
    ~Graduate() {
    
    }
    void Print() {
    
    
        Student::Print();
        cout << "advisor is:\t" << advisor_ << endl;
    }
    void PrintAdvisor() {
    
    
        cout << "advisor is:\t" << advisor_ << endl;
    }


    string advisor_;
};

class Teacher :virtual public Person {
    
    
public:
    Teacher() {
    
    }
    Teacher(string name, Gender_ gender, Birthday birth, string title) :Person(name, gender, birth) {
    
    
        title_ = title;
    }
    void Print() {
    
    
        Person::Print();
        cout << "title is:\t" << title_ << endl;
    }
    void PrintTitle() {
    
    
        cout << "title is:\t" << title_ << endl;
    }

    string title_;
};

class Assistant :public Graduate, public Teacher {
    
    
public:
    Assistant() {
    
    }
    Assistant(string name, Gender_ gender, Birthday birth, int score, string advisor, string title, string subject) :Person(name, gender, birth), Graduate(name, gender, birth, score, advisor), Teacher(name, gender, birth, title) {
    
    
        subject_ = subject;
    }
    void Print() {
    
    
        /*Graduate::Print();
        cout << "---\n";
        Teacher::Print();*/

        /*cout << "name is:" << Person::name_ << endl;
         cout << "gender is:" << Person::gender_ << endl;
         Person::birth_.print();
         cout << "score is:" << Student::score_ << endl;*/
        Student::Print();
        cout << "advisor is:\t" << Graduate::advisor_ << endl;
        cout << "title is:\t" << Teacher::title_ << endl;
        cout << "subjet is:\t" << subject_ << endl;


    }
    void PrintSubject() {
    
    
        cout << "subject is:\t" << subject_ << endl;
    }

    string subject_;
};

int main() {
    
    
    Birthday birthPerson(1000, 1, 1);
    Person person("Spinoza", Male, birthPerson);
    Birthday birthStudent(2021, 10, 28);
    Student student("Descartes", Male, birthStudent, 100);
    Birthday birthTeacher(1990, 10, 28);
    Teacher teacher("Leibniz", Male, birthTeacher, "Teaching Affairs");
    Birthday birthgraduate(2000, 2, 2);
    Graduate graduate("graduate", Male, birthgraduate, 99, "Teaching Affairs");
    Birthday birthassitant(1998, 8, 8);
    Assistant assitant("assitant", Male, birthassitant, 99, "advisor", "title", "subject");

    cout << "-------person------------\n";
    person.Print();
    cout << "-------student------------\n";
    student.Print();
    cout << "-------teacher------------\n";
    teacher.Print();
    cout << "-------Graduate------------\n";
    graduate.Print();
    //graduate.PrintAdvisor();
    cout << "-------Assitant------------\n";
    assitant.Print();
    //assitant.PrintSubject();

    Assistant test;
    Graduate* a = &test;
    Teacher* b = &test;
    Student* c = &test;
    Person* d = &test;
    Person* a1 = a;
    Person* a2 = b;
    Person* a3 = c;
    Person* a4 = &test;
    cout << a << "\n" << b << "\n" << c << "\n" << d << "\n" << a1 << "\n" << a2 << "\n" << a3 << "\n"<< a4<< "\n----------------" << endl;

    assitant.Teacher::Address();
    assitant.Person::Address();
    assitant.Student::Address();
    assitant.Graduate::Address();
    assitant.Address();

    assitant.name_ = "na";
    assitant.Person::name_ = "np";
    assitant.Graduate::name_ = "nG";
    assitant.Student::name_ = "nS";
    assitant.Teacher::name_ = "nT";

    cout << assitant.name_ << "\n" << assitant.Person::name_ << "\n" << assitant.Graduate::name_ << "\n" << assitant.Student::name_ << "\n" << assitant.Teacher::name_ << endl;


    return 0;

}

猜你喜欢

转载自blog.csdn.net/m0_45311187/article/details/121052431
今日推荐