多重繼承
多重繼承是指一個類繼承了多個基類。例如:
class ClassCadres : public Student , public Worker
{
...
};
ClassCadres
同時繼承了
Student
類和
Worker
類,
ClassCadres
同時擁有了
Student
和
Worker
的屬性。
多重繼承的問題
祖先相同的多重繼承。
例如:
Student
和
Worker
都繼承自
Person
類,而
ClassCadres
同時繼承了
Student
和
Worker
類。
這樣會産生兩個問題:
- 從兩個不同的基類繼承了同名方法;
- 産生多個祖先類對象。
執行個體一
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;
}
程式說明
- 運作程式列印了兩次"constructor",說明産生了兩個Person類對象。
- 如果c1直接使用
方法,将會産生二義性,是以需要指明是哪個對象的方法。HShow()
- 如果将将派生類對象位址賦給基類指針,也将産生二義性,是以需要指明轉為哪個對象。
使用虛基類可以解決多重繼承帶來的問題。
虛基類
虛基類使得從多個類(它們的基類相同)派生出的對象隻繼承一個基類對象。
通過在類聲明中使用關鍵字
virtual
,可以使
Person
類作為
Student
和
Worker
的虛基類:
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;
}
程式說明
- 從列印結果可知,"constructor"隻列印了一次,說明隻有一個基類對象。
- 新的構造規則:
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) {}
注意:如果類有間接虛基類,則除非隻需使用該虛基類的預設構造函數,否則必須顯示地調用該虛基類的某個構造函數。
- 其中定義了一個保護成員
,用來列印本類特有的屬性。隻可以在類内部使用,作為公有接口的輔助方法。HData()
- 使用作用域解析運算符來區分類方法
Person::HData();
Student::HData();
Worker::HData();