多重继承(MI)描述的是有多个直接基类的类。与单继承一样,共有MI表示的也是is-a关系。例如,可以从Awiter类和Singer类派生出SingingWaiter类:
class SingingWaiter : public Waiter, public Singer {...};
MI可能会给程序员带来很多新问题。其中两个主要的问题是:从两个不同的基类继承同名方法;从两个或更多相关基类那里继承同一个类的多个实例。
在下面的例子中,我们将定义一个抽象基类Worker,并使用它派生出Waiter类和Singer类。然后,使用MI从Waiter类和Singer类派生出SingingWaiter类。
程序清单14.7 worker0.h
// worker0.h -- working classes #ifndef WORKER0_H_ #define WORKER0_H_ #include <string> class Worker // an abstract base class { private: std::string fullname; long id; public: Worker() : fullname("no one"), id(0L) {} Worker(const std::string & s, long n) : fullname(s), id(n) {} virtual ~Worker() = 0; // pure virtual destructor virtual void Set(); virtual void Show() const; }; class Waiter : public Worker { private: int panache; public: Waiter() : Worker(), panache(0) {} Waiter(const std::string & s, long n, int p = 0) : Worker(s, n), panache(p) {} Waiter(const Worker & wk, int p = 0) : Worker(wk), panache(p) {} void Set(); void Show() const; }; class Singer : public Worker { protected: enum {other, alto, contralto, soprano, bass, baritone, tenor}; enum {VTypes = 7}; private: static char *pv[VTypes]; // string equivs of voice types int voice; public: Singer() : Worker(), voice(other) {} Singer(const std::string & s, long n, int v = other) : Worker(s, n), voice(v) {} Singer(const Worker & wk, int v = other) : Worker(wk), voice(v) {} void Set(); void Show() const; }; #endif // WORKER0_H_
程序清单14.7的类声明中包含一些表示声音类型的内部变量。一个枚举类型符号常量alto、contralto等表示声音类型,静态数组pv存储了指向相应C-风格字符串的指针,程序清单14.8初始化了该数组,并提供了方法的定义。
程序清单14.8 worker0.cpp
// worker0.cpp -- working class methods #include "worker0.h" #include <iostream> using std::cout; using std::cin; using std::endl; // Worker methods // must implement virtual destructor, even if pure Worker::~Worker() {} void Worker::Set() { cout << "Enter worker‘s name: "; getline(cin, fullname); cout << "Enter worker‘s ID: "; cin >> id; while(cin.get() != ‘\n‘) continue; } void Worker::Show() const { cout << "Name: " << fullname << "\n"; cout << "Employee ID: " << id << "\n"; } // Waiter methods void Waiter::Set() { Worker::Set(); cout << "Enter waiter‘s panache rating: "; cin >> panache; while (cin.get() != ‘\n‘) continue; } void Waiter::Show() const { cout << "Category: waiter\n"; Worker::Show(); cout << "Panache rating: " << panache << "\n"; } // Singer methods char * Singer::pv[] = {"other", "alto", "contralto", "soprano", "bass", "baritone", "tenor"}; void Singer::Set() { Worker::Set(); cout << "Enter number for singer‘s vocal range:\n"; int i; for (i = 0; i < VTypes; i ++) { cout << i << ": " << pv[i] << " "; if (i % 4 == 3) cout << endl; } if (i % 4 != 0) cout << endl; while (cin >> voice && (voice < 0 || voice >= VTypes) ) cout << "Please enter a value >= 0 and < " << VTypes << endl; while (cin.get() != ‘\n‘) continue; } void Singer::Show() const { cout << "Category: singer\n"; Worker::Show(); cout << "Vocal range: " << pv[voice] << endl; }
程序清单14.9是一个简短的程序,它使用一个多台指针数组对这些类进行了测试。
程序清单14.9 worktest.cpp
// worktest.cpp -- test worker class hierarchy #include <iostream> #include "worker0.h" const int LIM = 4; int main() { Waiter bob("Bob Apple", 314L, 5); Singer bev("Beverly Hills", 522L, 3); Waiter w_temp; Singer s_temp; Worker * pw[LIM] = {&bob, &bev, &w_temp, &s_temp}; int i; for (i = 2; i < LIM; i ++) pw[i]->Set(); for (i = 0; i < LIM; i ++) { pw[i]->Show(); std::cout << std::endl; } return 0; }
效果:
Enter worker‘s name: Waldo Dropmaster Enter worker‘s ID: 442 Enter waiter‘s panache rating: 3 Enter worker‘s name: Sylvis Sirenne Enter worker‘s ID: 555 Enter number for singer‘s vocal range: 0: other 1: alto 2: contralto 3: soprano 4: bass 5: baritone 6: tenor 3 Category: waiter Name: Bob Apple Employee ID: 314 Panache rating: 5 Category: singer Name: Beverly Hills Employee ID: 522 Vocal range: soprano Category: waiter Name: Waldo Dropmaster Employee ID: 442 Panache rating: 3 Category: singer Name: Sylvis Sirenne Employee ID: 555 Vocal range: soprano
这种设计看起来是可行的:使用Waiter指针来调用Waiter::Show()和Waiter::Set();使用Singer指针来调用Singer::Show()和Singer::Set()。然后,如果添加一个从Singer和Waiter类派生出的SingingWaiter类后,将带来一些问题。具体地说,将出现以下问题。
* 有多少Worker?
* 哪个方法?
时间: 2024-09-26 19:57:45