多重继承
多重继承是指一个类继承了多个基类。例如:
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();