类继承
类继承就是在已有类的基础之上,对这个类进行修改,可以给原有类增加数据和方法.,也可以修改原有类,增加代码复用的一种技术.
设计一个乒乓球俱乐部会员的类
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; } // 重置座位
};
TableTennisPlayer::TableTennisPlayer (const string & fn,
const string & ln, bool ht) : firstname(fn),lastname(ln), hasTable(ht) // 使用列表初始化
{
}
void TableTennisPlayer::Name() const
{
std::cout << lastname << ", " << firstname;
}
测试如下:
int main( )
{
using std::cout;
TableTennisPlayer player1("Chuck", "Blizzard", true); // 隐式初始化
TableTennisPlayer player2("Tara", "Boomdea", false);
player1.Name(); // 打印playper1的名字
if (player1.HasTable()) // 判断是否有位置
cout << ": has a table.\n";
else
cout << ": hasn't a table.\n";
player2.Name();
if (player2.HasTable())
cout << ": has a table";
else
cout << ": hasn't a table.\n";
return 0;
}
测试结果如下:
很简单的一段代码.
从TableTennisPlayer类派生出一个新类
下面将这个TableTennisPlayer类进行继承,首先要知道几个知识点.
-
从TableTennisPlayer类派生出RatedPlayer这个类,代码格式如下:
class RatedPlayer : public TableTennisPlayer
{
…
} -
这段代码指出,RatedPlayer这个类是从TableTennisPlayer派生出来的,这是一种公有派生,TableTennisPlayer为基类,称RatedPlayer为派生类.
-
并且派生类对象存储了基类的数据成员,而且派生类还继承了基类的接口,RatedPlayer对象还可以使用TableTennisPlayer类的Name(),hasTable(),ResetTAble()方法.
-
在派生类中既可以添加新的数据成员,又可以添加新的接口,但是派生类需要自己的构造函数.
给TableTennisPlayer类成员增加Rating项如下:
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::RatedPlayer(unsigned int r, const string & fn,
const string & ln, bool ht) : TableTennisPlayer(fn, ln, ht)
{
rating = r;
}
在函数名字后面加上基类构造函数就会先对基类构造函数进行初始化.
例如RatedPlayer rplayer1(1140, “Mallory”, “Duck”, true),相当于把"Mallory", “Duck”, true这几个参数传入TableTennisPlayer(fn, ln, ht)基类构造函数,将基类数据进行初始化.
若省略初始化构造函数,就会自动调用默认构造函数.
RatedPlayer::RatedPlayer(unsigned int r, const string & fn,
const string & ln, bool ht)
{
rating = r;
}
这样也会调用TableTennisPlayer(fn, ln, ht),因为这是所有参数带默认参数的构造函数,也就是默认构造函数.
派生类的复制构造函数
通过派生类的复制构造函数也可以对基类数据进行初始化,用已经存在的对象初始化新对象.
RatedPlayer::RatedPlayer(unsigned int r, const TableTennisPlayer & tp)
: TableTennisPlayer(tp), rating(r)
{
}
虽然基类没有定义复制构造函数,但是会自动生成一个,因为没有涉及到类中的数据动态分布,所以不用进行重新定义基类复制构造函数.
具体代码如下:
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; };
};
// 从TableTennisPlayer派生出RatedPlayer类
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;}
};
接口函数实现:
TableTennisPlayer::TableTennisPlayer (const string & fn,
const string & ln, bool ht) : firstname(fn),
lastname(ln), hasTable(ht) {}
void TableTennisPlayer::Name() const
{
std::cout << lastname << ", " << firstname;
}
// RatedPlayer接口实现
RatedPlayer::RatedPlayer(unsigned int r, const string & fn,
const string & ln, bool ht) : TableTennisPlayer(fn, ln, ht)
{
rating = r;
}
RatedPlayer::RatedPlayer(unsigned int r, const TableTennisPlayer & tp)
: TableTennisPlayer(tp), rating(r)
{
}
测试函数如下:
int main ( void )
{
using std::cout;
using std::endl;
TableTennisPlayer player1("Tara", "Boomdea", false); // 基类初始化
RatedPlayer rplayer1(1140, "Mallory", "Duck", true); // 派生类初始化
rplayer1.Name(); // 派生类对象可以使用公共接口
if (rplayer1.HasTable())
cout << ": has a table.\n";
else
cout << ": hasn't a table.\n";
player1.Name(); // 基类使用基类接口
if (player1.HasTable())
cout << ": has a table";
else
cout << ": hasn't a table.\n";
cout << "Name: ";
rplayer1.Name();
cout << "; Rating: " << rplayer1.Rating() << endl;
// 用player1对象初始化新的rplayer2的基类数据成员
RatedPlayer rplayer2(1212, player1);
cout << "Name: ";
rplayer2.Name();
cout << "; Rating: " << rplayer2.Rating() << endl;
return 0;
}
结果如下: