C++:类的设计————公有继承

1.继承的概念

继承是c++的特性,其含义是从已有的类派生出新的类,而派生的类继承了基类的一些私有成员和成员函数。

公有继承是最为常用的继承方式。

2.公有继承的特点

派生类的对象继承了基类的私有成员,但是不可以直接访问(派生类继承基类的实现)

派生类的对象可以使用基类的成员方法(派生类继承了基类的接口)。

继承的使用必须基于继承的这两个特点,举一个简单的例子。

假设有基类Player,描述一个运动员的姓名属性。

class Player
{
    private:
        std::string firstname;
        std::string lastname;
    public:
        Player(const std::string & fname = "none", const std::string & lname = "none") : firstname(fname), lastname(lname) {};
        void name() const;
        ~Player();
};

我们想设计一个新的类,这个类中除了运动员的姓名还要加入新的属性,运动员的排名。

因为这个新的类比起Player只多了rating属性和一些成员方法,那么我们就可以利用Player这个类来派生出新的类,提高代码的重用性。

class RatedPlayer : public Player
{
    private:
        unsigned int rating;
    public:
        RatedPlayer(const unsigned int r = 0, const std::string & fname = "none", const std::string & lname = "none");
        RatedPlayer(unsigned int r, const Player & pl);
        void reset_rating(unsigned int r = 0) {  rating = r ; };
};

公有继承的语法很简单,在派生类(RatedPlayer)的后边加冒号(:)后跟关键字public+基类名(Player)

3.需要在继承的特性中添加什么

派生类需要自己的构造函数(非常重要)。

派生类可以根据自己的需要添加新的私有成员和成员函数。

派生类的构造函数尤为重要,理解派生类的构造函数对于继承这一概念的了解会有很大帮助。

下面给出派生类的构造函数的函数体然后说明。

RatedPlayer::RatedPlayer(const unsigned int r, const std::string & fname, const std::string & lname) : Player(fname, lname), rating(r) {};

我们可以看出,在构造派生类的时候,我们使用了基类的构造函数,那么这是为什么呢?

首先,派生类不可以直接访问基类的私有成员,必须通过基类的方法,所以说RatedPlayer中的firstname、lastname只能通过基类的构造函数来进行初始化。

其次,创建派生类对象的时候,程序应当首先创建基类对象,因为没有基类哪来的派生类呢?

所以说,RatedPlayer中的构造函数中的Player(fname,lname)可以理解成先构造了基类对象,在这基础上又添加派生类对象的私有成员初始化。

那么,如果不调用基类的构造函数会怎么样呢?

即:

RatedPlayer::RatedPlayer(const unsigned int r, const std::string & fname, const std::string & lname)
{
    rating = r;
}

会怎么样呢?

注意,编译器始终遵循先创建基类对象后创建派生类对象的原则,所以说,上述代码等价于:

RatedPlayer::RatedPlayer(const unsigned int r, const std::string & fname, const std::string & lanme) : Player()
{
    rating = r;
}  

即调用基类对象的默认构造函数,如果不存在默认构造函数,那么就会出错。

除非要使用默认基类构造函数,否则应当进行显示调用。

公有继承要点如下:

•在创建派生类对象的时候应当首先创建基类对象。

•派生类构造函数应当通过成员初始化列表的方式将基类信息(即基类中的私有成员)传递给基类的构造函数。

•派生类构造函数应初始化派生类新增的数据成员。

其次还要着重说明一下,那就是派生类和基类之间的特殊关系。

除了派生类可以使用基类的方法这一关系外,还有三条重要的关系。

•基类指针可以在不进行显示转换的情况下指向派生类对象

•基类引用可以在不进行显示转换的情况下指向派生类引用

•同样的,可以将派生类对象赋值给基类对象而无需进行cast转换

#include "Player.h"
#include <iostream>
int main()
{
    RatedPlayer player(100,"Bob", "Brown");
    Player & pl = player;
    Player * p = &player;

    pl.name();
    p->name();
    getchar();
    return 0;
}

这三个特性非常好,我们可以只建立一种基类类型的指针数组存储派生类和基类对象批量处理。

实际上,公有继承建立一种is-a关系,即派生类是一种基类的特殊情况。

时间: 2024-07-29 15:14:38

C++:类的设计————公有继承的相关文章

C++进阶学习——线程基类的设计(Linux)

此示例是在Linux环境下(使用Linux系统编程线程相关函数)测试,文件说明如下: ThreadBase.cpp, ThreadBase.h为线程基类 ThreadDerive.cpp, ThreadDerive.h为测试派生类 main.cpp为测试程序 ThreadBase.h内容如下: #ifndef __THREADBASE_H__ #define __THREADBASE_H__ #include <pthread.h> //线程基类 class ThreadBase { publ

概念:类继承—公有继承、私有继承、保护继承

一.公有(Pulic)继承 “继承”是类的重要特性.A类继承B类,我们称B类为“基类”,也称为“父类”,A类则相应地被称为“派生类”或“子类”.A类继承了B类之后,A类就具有了B类的部分成员.那么,究竟从基类那儿得到了哪些成员,这由2方面决定,①继承方式,②基类成员的访问权限(即public/private/protected). 继承有三种方式,即公有(Public)继承.私有(Private)继承.保护(Protected)继承.我们先讨论最常用的公有继承.公有继承就是将基类的公有成员变为自

C++公有继承,私有继承和保护继承的区别

昨天学习三种继承方式,有些比喻十分形象,特此分享. 首先说明几个术语: 1.基类 基类比起它的继承类是个更加抽象的概念,所描述的范围更大.所以可以看到有些抽象类,他们设计出来就是作为基类所存在的(有些名字里面有abstract的). 基类也叫父类,虽然本人觉得这个比喻并不恰当.因为实际上子类是基类的扩充,描述了更加具体的东西.但现实的父子关系并非如此.但在有些方面这个比喻还是比较恰当的. 现在我们假设基类是一个快要退休的富豪.代码如下: class RichMan { public: RichM

多态公有继承

多态公有继承:所谓多态公有继承,就是同一个方法在派生类和基类中的行为不同. 实现多态公有继承的机制:1,在派生类重新定义基类的方法.(用于对象)2,使用虚方法(多用于指针和引用),虚方法在基类用关键字virtual声明,在派生类中会自动识别基类中声明的虚方法.所以,在派生类中可以用(也可以不用)virtual显式标出哪个方法是虚方法.通俗来讲:为了实现一种方法可以在派生类和基类中的行为不同,于是在派生类中重新定义基类函数的方法(比如基类有方法A, 但又在派生类中重新定义了方法A, 它们名字一样,

表达式计算器类的设计5(面向对象的表达式计算器8)

计算器的github下载地址:https://github.com/ljian1992/calculator 概述 表达式计算器的类基本已经设计完成了,由于在程序运行的时候总会有这样那样的异常,例如:a +2, a没有初始化,对于异常的管理一般而言是需要自定义异常类.这个自定义异常类也是在继承了系统已经定义好的exception类,然后再重新定义内容. 异常的种类 语法异常---->SyntaxError类 赋值时左操作数不是变量:1 = 2; 缺少括号:1 + (2*2 不认识的函数: 函数缺

表达式计算器类的设计4(面向对象的表达式计算器7)

概述 把符号表和变量表中的内容保存到一个文件中,通过IO文件流,来把符号表和变量表存储到文件中.在这之前需要弄明白什么是序列化和反序列化 对象的序列化 序列化:把对象转换为字节序列的过程 反序列化:把字节序列恢复为对象的过程 我们要把SymbolTable类的对象(符号表)和Storage类的对象(变量表)转换成字节序列保存到文件中,这时就可以设置Serializer类来完成这样的功能,同样的设置一个DeSerializer类来完成把保存到文件当中的字节序列恢复为对象的功能.这里要注意的是,所有

C++公有继承

is-a.has-a和like-a.组合.聚合和继承 两组概念的区别 - cbk861110的专栏 - 博客频道 -CSDN.NET http://blog.csdn.net/cbk861110/article/details/9028189 公有继承强调的是is-a的关系,强调的是一种继承关系,而has-a强调的是一种从属关系. 继承的形式为:  class  derived:public  based 公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的

表达式计算器类的设计1(表达式计算器4)

计算器的github下载地址:https://github.com/ljian1992/calculator 我们的最终目的是计算出表达式中的值,因此就需要定义一个抽象类用于计算表达式的值,该抽象类定义为:Node 下面所有的类图不使用UML建模语言画的,是通过visual studio自动生成的类关系图(自己用UML建模画的不小心被我删掉了) Node的类图 它继承了个Noncpyable类,由于我们是要做面向对象的表达式计算器,所以呢,通过一个小小的手段,把拷贝给禁止掉.这个小小的手段就是让

对【面向对象的类访问和对象访问的区别【this以及类访问】、静态成员的访问区别、类常量等、继承和重写、访问修饰限定符、冒泡排序】的总结

面向对象的总结1.首先面向对象的编程使用的都是使用对象作为处理对象而言[例如继承等情形,继承的本质来说,依旧针对的是对象]但是只有针对类的访问.静态成员以及访问修饰限定符时,针对的是类的概念 2.类内定义时,只有五种情形:类常量[const关键字定义并且使用类来调用]属性[这些属性和方法是针对该类实例的对象来调用]方法[在这种情形下使用$this进行指代作用环境(调用该方法的对象),只有继承中,子类实例的对象会向下传递到静态调用里]静态属性[用来作为实例该类的所有对象之间共享的数据.保存在类中]