1.派生一个类
```cpp
class TableTennisPlayer
{
private:
string firstname;
string lastname;
bool hasTable;
public:
TableTennisPlayer(const string& fn = "none",const string &ln = "none",bool ht = false);
void name() const;
bool HasTable() const { return hasTable; }
void ResetTable(bool v) { hasTable = v; }
};
class RatedPlayer :public TableTennisPlayer
{
private:
unsigned int rating;
public:
RatedPlayer(unsigned int r =0, const string& fn = "none", const string &ln = "none",bool ht = false);
RatedPlayer(unsigned int r, const TableTennisPlayer &tp);
unsigned int Rating() const { return rating; }
void ResetRating(unsigned int r) { rating = r; }
}
```
RatedPlayer对象将具有以下特征:
1.派生类对象存储了基类的数据成员(派生类继承了基类的实现);
2。派生类对象可以使用基类的方法(派生类继承了基类的接口);
因此,RatedPlayer对象可以存储运动员的姓名及其是否有球桌。另外,RatedPalyer对象还可以使用TableTennisPlayer类的Name(),hasTable(),ResetTable()方法。
构造函数必须给新成员(如果有的话)和继承的成员提供数据(简而言之:你都要继承别人的数据了,你能够使用别人的数据,所以你必须初始化你要使用的数据)。
在第一个Ratedplayer构造函数中,每个成员对应一个形参;而第二个RatedPlayer构造函数使用一个TableTennisPlayer参数,该参数包括firstname,lastname和hasTable。
2.构造函数:访问权限的考虑
RatedPlayer构造函数代码:
```cpp
RatedPlayer::RatedPlayer(unsigned int r, const string &fn, const string &ln, bool ht):TableTennisPlayer(fn,ln,ht)
{
rating = r;
}
```
派生类构造函数特点如下:
1.首先创建基类对象
2.派生类构造函数应通过成员初始化列表将基类的信息传递给基类的构造函数
3.派生类构造函数应初始化派生类新增的数据成员。
注意:
1.创建派生类对象时,程序首先调用基类构造函数,然后再调用派生类构造函数。基类构造函数负责初始化继承的数据成员;派生类构造函数用于初始化新增的派生类的数据成员。
2。派生类的构造函数总是调用一个基类构造函数。可以使用初始化列表指明使用的基类构造函数,否则将使用默认的构造函数。
3.派生类对象过期时,程序江县调用派生类的析构函数,然后调用基类的析构函数。
3.继承:is-a关系
派生类对象也是一个基类对象。
例如:香蕉是一种水果。那么我们可以从Friut类中派生出banana类。
banana is a kind of friut。
4.多态公有继承
1.在派生类中重新定义基类的方法
2.使用虚方法
5.派生类访问数据
派生类并不能直接访问基类的私有数据,而必须使用基类的公有方法才能访问这些数据。访问的方法取决于方法。
1.派生类构造函数在初始化基类私有数据时,采用的是初始化成员列表语法。
例:
Brassplus::Brassplus(const string &s , long an, double bal, double ml, double r):Brass(s,an,bal)
{
maxLoan = ml;
rate = r;
owesBank = 0.0;
}
Brassplus::Brassplus(const Brass &ba, double ml, double r):Brass(ba)
{
maxLoan = ml;
rate = r;
owesBank = 0.0;
}
2.非构造函数不能使用成员初始化列表语法,但派生类方法可以调用公有的基类方法。
例:
void Brassplus::ViewAcct() const
{
format initialState = setFormat();
precis prec = cout.precision(2);
Brass::ViewAcct();
cout << "Maximum loan: $" << maxLoan << endl;
cout << "Owed to bank:$" << owesBank << endl;
cout.precision(3);
cout << "Loan Rate:" << 100 * rate << "%\n";
restore(initialState, prec);
}
在派生类方法中,标准技术是使用作用域解析运算符来调用基类方法。
6.虚析构
使用虚析构函数可以确保正确的析构函数序列被调用。
7.早绑定与晚绑定
在编译过程中进行的联编被称为静态联编,也成为早期联编,既早绑定。
编译器必须生成能够在程序运行时选择正确的虚方法的代码,这被称为动态联编,也成为晚期联编。
指向基类的指针或引用可以指向派生类的对象。
仅将那些预期将被重新定义的方法声明为虚的。
使用虚函数时,在内存和执行速度方面有一定的成本,包括:
1.每个对象都将增大,增大量为存储地址的空间。
2.对于每个类,编译器都将创建一个虚函数地址表(数组);
3.对于每个函数调用,都需要执行一项额外的操作,即到表中查找地址。
8.虚函数注意事项
1.在基类方法的声明中使用关键字virtual,可使该方法在基类以及所有的派生类(包括从派生类派生出来的类)中是虚的。
2.如果使用指向对象的引用或指针来调用虚方法,程序将使用为对象类型定义的方法,而不使用为引用或指针类型定义的方法。这种被称为晚绑定。也就是基类的指针或引用指向派生类的对象。
3.如果定义的类被作为基类,则应将那些要在派生类中重新定义的类方法声明为虚的。
注意:通常应该给基类提供一个虚析构函数,即使它并不需要析构函数。
定义虚函数:
1.如果重新定义继承的方法,应确保与原来的原型完全相同,但如果返回类型是基类引用或指针,则可以修改为指向派生类的引用或指针
2.如果基类声明被重载了,则应在派生类中重新定义所以的基类版本。