PPC的C/C++和人工智能学习笔记
每一篇学习笔记,都只是为了更好地掌握和理解

C++语言基础(8)_类的继承

C++基础,今天学习类的继承

 

继承的概念:

一个新类从已有的类那里获得其已有特性,称为继承。

我们习惯用这样两对名字来描述他们:基类、派生类,父类、子类。已有的类称为基类或者父类,那个新类称为派生类或者子类。

 

声明派生类(子类)的一般形式:

class 派生类名: [继承方式] 基类名 {  //继承方式有:public protected private三种

派生类新增加的成员 }

 

构造一个派生类包括以下3部分工作:

(1) 从基类接收成员。派生类把基类全部的成员(不包括构造函数和析构函数)接收过来

(2) 调整从基类接收的成员。接收基类成员是程序员不能选择的,但是程序员可以对这些成员作某些调整。

(3) 在声明派生类时增加的成员。

 

三种继承方式:public protected private

先复习下类里面的三种成员访问属性:

public(公有属性): 该成员可以在类外直接使用,比如A.x这样的方式;

protected(保护属性):该成员不可以在类外直接使用,比如A.x是不允许的,但是可以在它的派生类中直接使用;

private(私有属性):该成员不可以在类外直接使用,也不可以在它的派生类中直接使用。

从上面可以看出:从严格性角度看,私有>保护>公有

那么对于继承方式:不管基类的访问属性是什么,也不管派生类去继承方式是什么,谁更严格,这个成员在派生类中就是什么访问属性

补充小知识:为了实现类的私有成员数据在外面可以直接用类似A.x的方式访问,而不是通过接口函数去访问,同时又要加上数据有效性检测,可以通过如下方法:

#include <iostream>
using namespace std;

class A {
private:
 char m_sex; //私有属性,只允许为'm'和'w'。
public:
 void setSex(char sex) { //常规写法,设置sex的接口函数
 if (sex == 'm' || sex == 'w') //数据有效性检测
 m_sex = sex;
 else {
 m_sex = 'm'; //默认为 'm'
 }
 }
 char getSex() const { return m_sex; } //常规写法,获取sex的接口函数
 //下面是特殊写法:加上这个可以直接 a.sex访问了
 _declspec(property(get = getSex, put = setSex))char sex; //名字要和m_sex不同
};

int main() {
 A a;
 a.sex = 'w';
 cout << a.sex << endl; //输出w
 a.sex = 's';
 cout << a.sex << endl; //输出m(因为有效性检测)
 return 0;
}

public继承:派生类在类内类外的访问权限的例子。

//public继承:类内类外的访问权限例子
class A {
private:
 int z;
protected:
 int y;
public:
 int x;
};

class B :public A {
public:
 void SetXYZ(){
 x = 1; //public继承,基类是public访问属性,类内可以直接访问
 y = 1; //public继承,基类是protected访问属性,类内可以直接访问
 //z = 1; //public继承,基类是private访问属性,类内不可以直接访问
 }
};

int main() {
 B b;
 b.x = 1; //public继承,基类是public访问属性,类外可以直接访问
 //b.y = 2; //public继承,基类是protected访问属性,类外不可以直接访问
 //b.z = 3; //public继承,基类是private访问属性,类外不可以直接访问
 return 0;
}

protect继承:派生类在类内类外的访问权限的例子。

//protected继承:类内类外的访问权限例子
class A {
private:
 int z;
protected:
 int y;
public:
 int x;
};

class B :protected A {
public:
 void SetXYZ(){
 x = 1; //protected继承,基类是public访问属性,类内可以直接访问
 y = 1; //protected继承,基类是protected访问属性,类内可以直接访问
 //z = 1; //protected继承,基类是private访问属性,类内不可以直接访问
 }
};

int main() {
 B b;
 //b.x = 1; //protected继承,基类是public访问属性,类外不可以直接访问
 //b.y = 2; //protected继承,基类是protected访问属性,类外不可以直接访问
 //b.z = 3; //protected继承,基类是private访问属性,类外不可以直接访问
 return 0;
}

private继承:派生类在类内类外的访问权限的例子。

//private继承:类内类外的访问权限例子
class A {
private:
 int z;
protected:
 int y;
public:
 int x;
};

class B :private A {
public:
 void SetXYZ(){
 x = 1; //private继承,基类是public访问属性,类内可以直接访问
 y = 1; //private继承,基类是protected访问属性,类内可以直接访问
 //z = 1; //private继承,基类是private访问属性,类内不可以直接访问
 }
};

int main() {
 B b;
 //b.x = 1; //private继承,基类是public访问属性,类外不可以直接访问
 //b.y = 2; //private继承,基类是protected访问属性,类外不可以直接访问
 //b.z = 3; //private继承,基类是private访问属性,类外不可以直接访问
 return 0;
}

继承分为:单继承、多继承

单继承,就是一个新类只继承于一个类;

多继承,就是一个新类继承于多个类。

如:class C:public A, private B{}

多继承的成员访问属性与单继承类似。

 

由于在继承的时候,构造函数和析构函数是不继承的,所以,我们来看一下一个类在继承其他类的时候,它的构造次序是如何的。

为了能够更加有代表性,我们在这个类中加入了子对象。

结论:创建一个类的时候,首先看有没有基类,如果有,按从左往右的声明顺序依次构造基类;接下来看有没有子对象,如果有,按从上往下的声明顺序依次构造子对象;最后是构造自身;析构则反向

验证:

//验证类的构造次序
#include <iostream>
using namespace std;
class BASE {
public:
 BASE() { cout << "基类构造BASE()" << endl; }
 ~BASE(){ cout << "基类析构~BASE()" << endl; }
};
class TOOLS {
public:
 TOOLS(){ cout << "子对象构造TOOLS()" << endl; }
 ~TOOLS(){ cout << "子对象析构~TOOLS()" << endl; }
};
class A :public BASE {
public:
 A() { cout << "自身构造A()" << endl; }
 ~A() { cout << "自身析构~A()" << endl; }
private:
 TOOLS t;
};

int main() {
 A a;
 return 0;
 //输出:
 //基类构造BASE()
 //子对象构造TOOLS()
 //自身构造A()
 //自身析构~A()
 //子对象析构~TOOLS()
 //基类析构~BASE()
 //请按任意键继续. . .
}

练习:用类的继承实现三个类,商店NPC,任务NPC,怪物NPC。

//练习:用类的继承实现三个类,商店NPC,任务NPC,怪物NPC。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
using std::cout;
using std::endl;

enum { shopNPC, taskNPC, monsterNPC };

class CBaseNpc { //npc基类
protected:
 int m_id; //npc编号
 char m_name[40]; //npc姓名
public:
 CBaseNpc() {}
 ~CBaseNpc() {}
public:
 _declspec(property(get = GetID, put = SetID))int id;
 void SetID(int id) { m_id = id; }
 int GetID() const { return m_id; }
 void SetName(const char* name) { strcpy(m_name, name); }
 const char * GetName() const { return m_name; }
};

class CShopNpc:public CBaseNpc { //商店类npc
private:
 int m_type; //npc类型
 int m_shoplist[10][2]; //商品列表
public:
 CShopNpc() {}
 ~CShopNpc() {}
public:
 _declspec(property(get = GetType, put = SetType))int type;
 int GetType() const { return m_type; }
 void SetType(int type) { m_type = type; }
 void NpcAction() { cout << "商品列表:" << endl; }
};

class CTaskNpc :public CBaseNpc { //任务类npc
private:
 int m_type; //npc类型
 int m_tasklist[10][2]; //任务列表
public:
 CTaskNpc() {}
 ~CTaskNpc() {}
public:
 _declspec(property(get = GetType, put = SetType))int type;
 int GetType() const { return m_type; }
 void SetType(int type) { m_type = type; }
 void NpcAction() { cout << "任务列表:" << endl; }
};

class CMonsterNpc :public CBaseNpc { //任务类npc
private:
 int m_type; //npc类型
 int m_exp; //npc经验
 int m_skills[5]; //npc技能
public:
 CMonsterNpc() {}
 ~CMonsterNpc() {}
public:
 _declspec(property(get = GetType, put = SetType))int type;
 int GetType() const { return m_type; }
 void SetType(int type) { m_type = type; }
 void NpcAction() { cout << "开始战斗吧:" << endl; }
};

int main() {
 CShopNpc NpcA;
 NpcA.id = 1;
 NpcA.SetName("铁匠铺老板");
 NpcA.type = shopNPC;
 cout << "id=" << NpcA.id << ",name=" << NpcA.GetName() << ",type=" << NpcA.type << endl;
 //输出:id = 1, name = 铁匠铺老板, type = 0
 NpcA.NpcAction(); //输出 商品列表:

 CTaskNpc NpcB;
 NpcB.id = 2;
 NpcB.SetName("悬赏接单处");
 NpcB.type = taskNPC;
 cout << "id=" << NpcB.id << ",name=" << NpcB.GetName() << ",type=" << NpcB.type << endl;
 //输出:id = 2, name = 悬赏接单处, type = 1
 NpcB.NpcAction(); //输出 任务列表:

 CMonsterNpc NpcC;
 NpcC.id = 3;
 NpcC.SetName("九幽老魔");
 NpcC.type = monsterNPC;
 cout << "id=" << NpcC.id << ",name=" << NpcC.GetName() << ",type=" << NpcC.type << endl;
 //输出:id = 3, name = 九幽老魔, type = 2
 NpcC.NpcAction(); //输出 开始战斗吧:
 return 0;
}

(2017-03-23 www.vsppc.com)

学习笔记未经允许不得转载:PPC的C/C++和人工智能学习笔记 » C++语言基础(8)_类的继承

分享到:更多 ()

评论 抢沙发

评论前必须登录!