天天看點

C++多重繼承和虛基類的學習多重繼承虛基類

多重繼承

多重繼承是指一個類繼承了多個基類。例如:

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

ClassCadres

同時繼承了

Student

類和

Worker

類,

ClassCadres

同時擁有了

Student

Worker

的屬性。

多重繼承的問題

祖先相同的多重繼承。

例如:

Student

Worker

都繼承自

Person

類,而

ClassCadres

同時繼承了

Student

Worker

類。

C++多重繼承和虛基類的學習多重繼承虛基類

這樣會産生兩個問題:

  • 從兩個不同的基類繼承了同名方法;
  • 産生多個祖先類對象。

執行個體一

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

類作為

Student

Worker

的虛基類:

class Student : virtual public Person { ... };
class Worker : public virtual Person { ... };   // virtual和public順序無關緊要
class ClassCadres : public Student, public Worker 
{ 
    ... 
};  // ClassCadres将隻包含一個Person對象
           
C++多重繼承和虛基類的學習多重繼承虛基類

執行個體二

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();
           

繼續閱讀