系列文章目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、多重继承14.3
MI描述的是有多个直接基类的类。与单继承一样,公有 MI表示的也是is-a关系。例如,可以从 Waiter类和 Singer 类派生出 SingingWaiter 类:
class SingingWaiter :public waiter,public singer…};
请注意,必须使用关键字 public 来限定每一个基类。这是因为,除非特别指出,否则编译器将认为是
私有派生:class SingingWaiter : public waiter,Singer (…);// Singer is a private base正如本章前面讨论的,私有 M和保护MI可以表示 has-a关系。Student 类的 studenti.h 实现就是一个
这样的示例。下面将重点介绍公有MI。MI可能会给程序员带来很多新问题。其中两个主要的问题是:从两个不同的基类继承同名方法;从两个或更多相关基类那里继承同一个类的多个实例。为解决这些问题,需要使用一些新规则和不同的语法。因此,与使用单继承相比,使用MI更困难,也更容易出现问题。由于这个原因,很多C++用户强烈反对使用 M,一些人甚至希望删除 MI;而喜欢 MI的人则认为,对一些特殊的工程来说,MI很有用,甚至是必不可少的;也有一些人建议谨慎、适度地使用MI。
下面来看一个例子,并介绍有哪些问题以及如何解决它们。要使用M1,需要几个类。我们将定义一个抽象基类 Worker,并使用它派生出 Waiter 类和 Singer 类。然后,便可以使用 MI从 Waiter 类和 Singer 类派生出 SingingWaiter 类(参见图14.3)。这里使用两个独立的派生来使基类(Worker)被继承,这将导致 MI的大多数麻烦。首先声明 Worker、Waiter和 Singer 类,如程序清单 14.7 所示。
二、程序清单14.7 Worker0.h
// Worker0.h -- working classes
#ifndef WORKER0_H_
#define WORKER0_H_
#include <string>
class Worker
{
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:
const static char *pv[Vtypes];
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
程序清单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
const 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()
{
using std::cout;
using std::cin;
using std::endl;
Waiter bob("Bob Apple", 3200, 5);
Singer bev("Beverly Hills", 3200, 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();
cout << endl;
}
cout << "Bye.\n";
return 0;
}
总结
提示:这里对文章进行总结:
这种设计看起来是可行的:使用Waiter指针来调用Waiter::Show()和 Waiter::Set();使用 Singer 指针来调用 Singer::Show( )和 Singer::Set( )。然后,如果添加一个从 Singer 和 Waiter 类派生出的 SingingWaitei类后,将带来一些问题。具体地说,将出现以下问题。
有多少 Worker?
哪个方法?