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

C++多继承与虚基类详解 含实例_第1张图片
虚基类版本:

#include
#include
#include
#include
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;

}

非虚基类:
发现有歧义部分的都报错了,比如不知道通过哪个途径向上转型。
C++多继承与虚基类详解 含实例_第2张图片
C++多继承与虚基类详解 含实例_第3张图片C++多继承与虚基类详解 含实例_第4张图片
可以看到向上转型,基类指针指向的是同一个对象。

#include
#include
#include
#include
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;

}

C++多继承与虚基类详解 含实例_第5张图片
可以看到向上转型,不同继承路线上的基类指针指向的是不同对象。
具体为什么person-student-graduate路线上的指针指向的是同一个对象,我们继续验证。

C++多继承与虚基类详解 含实例_第6张图片
进一步验证

#include
#include
#include
#include
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,另外三个始终打印最后赋值的那个。可以看出对象有两块内存区域,分别存储两条继承线路上的值。所以我们多用了一块内存。浪费了空间,造成了歧义。
C++多继承与虚基类详解 含实例_第7张图片
进一步验证:
加上虚基类:
C++多继承与虚基类详解 含实例_第8张图片
这两个方法不再报错了。
向上转型,有虚基类的情况下,所有基类指针还是均指向同一对象。
并且所有成员变量只有一块内存(即此处nT是最后一次赋上的值),所以我们节省了一块内存。
C++多继承与虚基类详解 含实例_第9张图片
代码如下:

#include
#include
#include
#include
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;

}

你可能感兴趣的:(C++,实例,c++,开发语言,后端,实例,继承)