C++基础(C++Primer学习)

C++基础(十)
<第十三章 类的继承>
类的继承使得类能够从已有的类派生出新的类,而派生类继承了原有类(基类)的特征,包括方法。

一、创建一个基类与其派生类
上面说了派生类可以继承基类的特征和方法,下面先创建一个类,然后在其基础上创建一个派生类(在Python里面,这对关系叫父类与子类,基类作为父类)。
1、首先创建基类的头文件及.cpp文件
头文件:

#pragma once
#include"list.h"
class Tabtenn
{
private:
	string firstname;
	string lastname;
	bool hasTable;
public:
	Tabtenn(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; }

};

.cpp文件:

#include "Tabtenn.h"

Tabtenn::Tabtenn(const string& fn ,
	const string& ln,
	bool ht )
{
	firstname = fn;
	lastname = ln;
	hasTable = ht;
}

void Tabtenn::name()const
{
	cout << lastname << endl;
}

该类记录的球员的姓名和一个状态(是否有球桌),然后其包含的接口函数就是可以打印当前的球员的姓名。
2、创建一个派生类
上面的类明显结构简单而且功能单一,现在需要另外一个类来记录球员的得分,如果还是从头开始定义相关的名字等信息的话明显是浪费的,使用类继承可以节省时间。
创建一个派生类的空架构:

class Rateplayer :public Tabtenn
{
	....
};

Rateplayer是Tabtenn的派生类,其对象将具有以下特性:
派生类对象存储了基类的数据成员
派生类对象可以使用基类的方法

因此Rateplayer的对象可以存储球员的姓名和是否有球桌,还能使用基类的成员函数。
思考:派生类作为类,同样需要自己的构造函数,同时派生类其实可以看作是基类的一种扩充,它可以根据需要来添加额外的数据成员和成员函数。
3、派生类的构造函数权限
如果派生类继承了基类的特性,那么能不能在派生类的构造函数里面初始化基类的数据值呢,这样岂不是更加方便?
派生类不能直接访问基类的私有成员,而必须通过基类的方法进行访问,这样的话在派生类里面使用基类的构造函数,不就可以对基类实现初始化了吗
创建派生类对象时,程序首先创建基类对象(这时应当的,不然去哪继承特性呢), 所以可以这样写派生类的构造函数:

Rateplayer::Rateplayer(int r, const string& fn, const string& ln, bool ht) :Tabtenn(fn, ln, ht)
{
	rating = r;
}

在构建派生类对象时,顺便也把基类对象构建了并初始化了。在这里如果不调用基类的构造函数的话,系统还是会调用默认的基类构造函数,为了避免不必要的错误,应当显式的调用默认的基类构造函数。

二、使用基类与派生类
使用之前,继续完善我们之前创建的派生类。

class Rateplayer :public Tabtenn
{
private:
	int rating;
public:
	Rateplayer(int r, const string& fn, const string& ln, bool ht);
	void show_rating()const;
};

其函数的定义,我也写在了Tabtenn类的.cpp文件中:

Rateplayer::Rateplayer(int r, const string& fn, const string& ln, bool ht) :Tabtenn(fn, ln, ht)
{
	rating = r;
}

void Rateplayer::show_rating()const
{
	cout<<"rating is: " << rating << endl;
}

添加了一个int型数据来存储当前球员的分数,然后再main函数内,创建一个派生类对象:

int main()
{
	Rateplayer player1(100, "jeck", "mass", false);
	cout << player1.Hastable() << endl;
	player1.show_rating();
	......

player1对象并不属于Tabtenn类,但是由于是其派生类,因此可以调用其中的成员函数。
思考:创建派生类对象时,基类的对象在那里存储呢,怎样访问?
另外一种派生类的构造函数的书写:

Rateplayer::Rateplayer(int r, const Tabtenn&t): Tabtenn(t)
{
	rating = r;
}

这样写的话,相当于我们给一个已知的基类对象创建派生类对象,并且该派生类对象将会继承基类对象的特性。传入的参数为基类对象的引用,该构造函数会调用基类的默认复制构造函数,将对象的值复制给创建的临时对象,再由派生类对象继承。
使用刚才创建的构造函数:

int main()
{
	Rateplayer player1(100, "jeck", "mass", false);
	Tabtenn player2("male", "jone", true);
	Rateplayer player3(990, player2);
	player3.name();

思考:实际创建构造函数时,构造函数应当尽可能多的包含不同情况,这样程序才能更加灵活
派生类构造函数的特点如下:
(1)、首先会创建一个基类对象
(2)、派生类构造函数应通过成员初始化列表将基类信息传递给基类构造函数
(3)、派生类构造函数应初始化派生类新增的数据成员。
笔记:之前说过对于一个类来说,其构造函数与析构函数都是必须的,如果没有显式的定义,那么系统将会默认执行。但是创建的顺序与释放的顺序时相反的,这类似于堆栈,即–先入后出

三、派生类与基类的关系探究
派生类与基类之间有一些特殊关系,其中之一就是派生类对象可以使用基类的方法(成员函数),条件是该方法不是私有成员。
另外两个重要关系是:基类指针可以在不进行显式类型转换的情况下指向派生类对象;基类引用可以在不进行显式类型转换的情况下引用派生类对象。(难懂)

int main()
{
	Rateplayer player1(100, "jeck", "mass", false);
	Tabtenn player2("male", "jone", true);
	Rateplayer player3(990, player2);
	Tabtenn& rt = player1;
	Tabtenn* pt = &player1;

也就是这两种写法都是可以的,该种引用和指针虽然声明为Tabtenn类型,但是其指向的内容却是它的派生类对象。
然而,基类指针或者引用只能用于调用基类方法,因此上面的引用和指针不能调用派生类中的成员方法。
在这里插入图片描述
可以看到不包含派生类中定义的成员函数。
总结一下就是虽然指向的对象是派生类对象,但是只能调用基类的方法。

思考:前面提到了一个问题就是如果单独创建派生类对象,那么系统首先创建的基类对象该怎么访问呢?使用上面的操作,就可以单独操作基类对象内的方法了。
此外,不可以将基类对象和地址赋给派生类引用和指针。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值