C++学习 十五、类继承(1)基类,派生类,访问权限,protected

前言

本篇开始学习C++类的继承。

类继承

C++的类继承用于描述一种is的关系。is关系,比如橘子是水果,猴子是动物。

类S是另一个类F的衍生,通过类继承的关系,就能够在F类的基础上,增量修改得到类S。类F称为基类,S称为派生类

派生类继承了基类的数据和方法,并且能够添加数据和方法。

类的关系与继承

类与类的关系决定了是否适合继承。

b is a关系:橘子是水果。
b has a关系:晚餐有水果。
b uses a关系:空调使用遥控。
b is like a关系:空调类似洗衣机(都是家具)。

上面的关系中,is关系适合使用b类继承a类;has关系适合在类b中使用a作为数据成员;uses关系适合将类b作为a的友元;is like关系适合定义一个包含a,b共有特征的类c,然后考虑c与a,b的关系。

基类, 派生类

基类

被继承的类是基类,可以按照之前定义类的方法,提供数据成员和方法。这里直接提供一个简单的基类Base:

class Base{
    private:
        int a_;
        double b_;
    public:
        Base();
        Base(int, double);
        void print();
};

Base::Base():a_(1), b_(1.){
    std::cout << "Base default constructor\n";
}

Base::Base(int a, double b): a_(a), b_(b){
    std::cout << "Base constructor\n";
}

void Base::print(){
    std::cout << a_ << " " << b_ << std::endl;
}

派生类

继承声明为:
class 派生类名 : 继承方式 基类名 {};,如class Derived : public Base {};

继承方式限定了派生类对基类成员的访问权限。public继承,基类的公有成员能够被派生类访问,但基类的私有成员只能被基类的公有方法和保护方法访问。

派生类将继承基类的所有数据成员以及成员函数。派生类还可以添加额外的成员

派生类虽然继承了基类的构造函数,但需要定义自己的构造函数

下面从Base类派生一个Derived类:

class Derived : public Base{
    private:
        int a_;
        double c_;
    public:
        Derived();
        Derived(int, double, int, double);
        void print();
};

Derived::Derived(): Base(), a_(1), c_(1.){
    std::cout <<"Derived default constructor\n";
}

Derived::Derived(int a0, double b, int a1, double c)
:Base(a0, b), a_(a1), c_(c) {
    std::cout <<"Derived constructor\n";
}

void Derived::print(){
	Base::print();
    std::cout <<a_ << " " << c_ << std::endl;
}

构造函数,析构函数

创建派生类对象时将调用派生类的构造函数,因此必须为派生类提供构造函数。派生类的构造函数应当为添加的数据成员和继承的数据成员初始化。

后面访问权限中会提到,派生类不能直接访问基类的私有成员,必须通过基类方法来访问。派生类的构造函数必须调用基类构造函数

构造函数Derived::Derived()是手动提供的默认构造函数,在成员初始化列表中调用了基类的构造函数Base()

创建派生类对象时,程序会首先创建基类对象,然后再创建派生类对象

Derived son1(2, 2.2, 3, 3.3);
/*
Base constructor
Derived constructor
2 2.2
3 3.3
Derived destructor
Base destructor
*/

上面的语句将参数传入派生类构造函数Derived(int a0, double b, int a1, double c),然后Derived函数调用基类构造函数Base(int, double),创建了一个嵌套的Base对象,存储基类的数据Base::a_, Base::b;然后再回到派生类构造函数,创建一个Derived对象,存储派生类的数据Derived::a_, Derived::c_

在派生类对象过期时,程序首先调用派生类析构函数,再调用基类析构函数。

派生类构造函数的成员初始化列表如果没有显式调用基类构造函数,创建对象时将调用基类的默认构造函数

Derived son2;
/*
Base default constructor
Derived default constructor
Derived destructor
Base destructor
*/

注意:如果创建派生类对象时,要指定继承成员的值,则必须在派生类构造函数的成员初始化列表中调用基类构造函数。派生类构造函数一定会调用一个基类构造函数

小结一下派生类的构造函数:

  • 首先向基类构造函数传参
  • 创建基类对象,基类对象存储继承成员值
  • 随后创建派生类对象,派生类对象存储添加成员的值

文件位置

编译器必须在声明派生类前知道基类的结构。因此,通常把基类声明和派生类声明放在同一个头文件中,把基类和派生类方法定义放在同一个源文件中。

访问权限

类继承中的一大难点在于,继承后派生类对基类成员的访问权限。

继承方式包括publicprotectedprivate三类。不过绝大多数情况,都使用public继承。

对于类自身的成员而言:

成员访问权限成员可见性
public能直接被外部访问
protected能被该类和子类的方法访问
private仅能被该类的方法访问

当派生类继承基类时,根据不同的继承方式,派生类对基类成员的访问权限将发生变化:

基类成员访问权限 \ 继承方式public 继承protected 继承private 继承
public 权限publicprotectedprivate
protected 权限protectedprotectedprivate
private 权限privateprivateprivate

protected

protected权限是与继承密切相关的访问权限。protected成员不能被外部直接访问,但可以被该类以及子类的成员函数访问。protected使得派生类能够使用公众不能使用的内部成员。

注意:如果希望限制数据的可见性,则最好使用private访问权限而不是protected,并且提供派生类能够调用的基类方法来访问基类的数据。

后记

下篇学习类的继承,虚函数与多态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值