C++(继承与派生(补充中)

五、继承与派生
1、继承与派生的概念

基类也可以叫做父类, 派生类可以叫做子类

继承、 派生 这两个词都是指的是传递关系, 只不过继承是站在子类角度说的, 派生是站在父类角度说的

为什么要使用继承,设计一个新类的时候可以继承父类的成员,减少设计类的冗余开发, 从而较好的解决了代码重用的问题

最高层(基类) : 是最普遍、 最一般的

底层(派生类) : 比它的上一层更具体, 并且含有高层的特性(继承) , 同时也与高层有细微不同

2、派生的方式

一般格式:
                       class 派生类名:派生方式 基类名

                                        {
                                                       //派生类新增的数据成员和成员函数
                                                };

class employee:public person{
private:
    char department[20];
    float salary;
public:
    //...
};
employee 类继承 person 类,也可以说 person 类派生出了 employee 类。

在声明派生类时, 根据”派生方式”所写的关键字不同可以分为三种派生方式
               a. 用 public 关键字的为 公有派生方式
               b. 用 private 关键字的为 私有派生方式
               c. 用 protected 关键字的为 保护派生方式

从继承源上分

                          1.单继承:每个派生类只直接继承了一个基类的特征
                          2. 多继承:多个基类派生出一个派生类的继承关系, 多继承的派生类直接继承了不止一个基类的特征。
 

class employee:public person,public animal
{
    char department[20];
    float salary;
    public:
    //...
};
3、公有派生(public)

class employee:public person{
    char department[20];
    float salary;
    public:
    //...
};
基类中的私有成员在派生类中不可访问,不可见;基类中的共有成员在派生类中仍是公有的,可以访问

派生后,可以通过基类中的公有成员函数访问基类中的私有成员

定义派生类构造函数时,要使用类似于对象成员的定义方式,参数列表写基类的名称

class Base{
private:
    int x;
public:
    Base(int x);
    void setX(int x);
    int getX(void);
    ~Base();
};
class Derive:public Base{//公有派生
private:
    int y;
public:
    Derive(int x,int y);//构造函数, 一定要有参数列表,只能写基类的类名称
    void setY(int y);
    int getY(void);
    ~Derive();//析构函数
};
Derive::Derive(int x,int y):Base(x)//在定义派生类构造函数时, 参数列表, 只能写基类的名称
{
    this->y=y;
    cout<<"Derive 中的 构造函数"<<endl;
}
构造的时候先构造基类再构造派生类;析构的时候先析构派生类再析构基类

.实例化对象的时候, 先给基类开辟空间, 再给派生类扩展部分开辟空间

4、私有派生

class employee:private person{
    char department[20];
    float salary;
public:
    //...
};
基类中的私有成员派生类中不能访问,基类中的公有成员在派生类中是私有成员

私有派生和公有派生的构造函数是一样的

5、保护成员的作用

在不涉及派生的时候保护成员和私有成员是一样的;在涉及到派生的时候, 基类中私有成员, 无论是什么样的派生方式, 在派生类中都是不可见;

有时候咱们想让基类中的私有成员在派生类的成员函数中可以用, 私有成员是不可以的, 那咱们可以将基类中的私有成员声明成保护成员。 基类中的保护成员在派生中是可见的是可以用的。

在公有派生时,基类中的保护成员在派生类中仍是保护的;基类中的私有成员, 在派生类中是不能访问的

在私有派生时,基类中的保护成员在派生类中是私有的

6、保护派生

class employee:protected person

{

          //…

};

基类中的私有成员在派生类中是不可见的不可访问;基类中的公有成员在派生类中是保护的

基类中的保护成员在保护派生之后还是保护的

7、派生后的访问权限总结

派生方式    
公有派生public

私有派生private

保护派生protected 

基类属性
私有    不能访问    不能访问    不能访问
保护    保护    私有    保护
公有    公有    私有    保护
8、多继承 

多继承可以看做是单继承的扩展。 所谓多继承是指派生类具有多个基类, 派生类与每个基类之间的关系仍可看做是一个单继承

多继承下派生类的定义格式如下:
                                 class 派生类名:继承方式 1 类名 1,继承方式 2 类名 2,....
                                 {//派生类体
                                 };

其中继承方式为public、private和protected之一

#include <iostream>
using namespace std;
class Point{
public:
    void setXY(int a, int b)
    {
        x = a;
        y = b;
    } 
    int getX()
        {return x;} 
    int getY()
        {return y;}
private:
    int x;
    int y;
};
class Line{
public:
    void setL(int a)
    {
        l = a;
    } 
    int getL()
        {return l;}
private:
    int l;
};
class Face:public Point,public Line{ //以公有方式派生出 Face
public:
    void setM(int a)
        {m = a;}
    int getM()
        {return m;}
private:
    int m;
};
int main()
{
    Point cc;
    cc.setXY(2,3);
    cout<<cc.getX()<<","<<cc.getY()<<endl;
    cout<<"------------------\n";
    Face f;//定义 Face 对象
    f.setXY(4,5);
    f.setL(6);
    f.setM(7);
    cout<<f.getX()<<","<<f.getY()<<","<<f.getL()<<","<<f.getM()<<endl;
    return 0;
}
在使用多继承是要注意避免发生二义性,两个父类中有可能有名字相同的数据成员或者成员函数

解决方法是:

                   c1.A::print();//调用 A 的 print
                  或者 c1.B::print();//调用 B 类中的 print

在 C 公有继承 A 和 B, 当 A 和 B 都公有继承 D 时, 这使得 A 和 B 都有 D 的公有部分, 在 C 中使用 D 的公有部分时, 编译器就会不确定是调用 A 的还是调用 B 的 而出现错误。因此要使用作用域预算符

#include<iostream>
using namespace std;
class D{
public:
    int d;
};
class A:public D{
public :
    int a;
};
class B:public D{
public :
    int b;
};
class C:public A,public B{
public :
    int c;
};
int main()
{
    C ob;
    ob.c=100;
    cout<<"ob.c= "<<ob.c<<endl;
    ob.A::d=200;
    cout<<"ob.d= "<<ob.A::d<<endl;
    return 0;
}
9、派生类的构造函数和析构函数

基类都有构造函数和析构函数, 或是显式定义、 或是隐式定义

派生类构造和析构函数的执行顺序:先构造基类, 再构造派生类。 先析构派生类, 再析构基类

当基类的构造函数没有参数(或全部默认值) 或没有显式的定义构造函数时, 那么派生类可以不向基类传递参数, 可以不定义构造函数

当基类含有带参数的构造函数时, 派生类必须定义构造函数, 以提供把参数传递给基类构造函数的途径

派生类构造函数的一般格式
                                派生类构造函数名(参数表 0):基类构造函数名(参数表 1)
                                {//......
                                }

参数表 1 是参数表 0 的子集

当派生类中含有对象成员时, 其构造函数的一般形式为
                              派生类构造函数名(参数表 0):基类构造函数名(参数表 1),
                                                                            对象成员名 1(参数表 2),....,
                                                                            对象成员名 n(参数表 n+1)
                                                                            {//......
                                                                            }

在定义派生类对象时构造函数的执行顺序是:基类->对象成员->派生类

                                 析构函数的执行顺序是:派生类->对象成员->基类

#include <iostream>
using namespace std;
class Base{
private:
    int x;
public:
    Base(int i){
        x = i;
        cout<<"构造 base 类, x="<<x<<endl;
    } 
    ~Base(){
        cout<<"析构 base 类, x="<<x<<endl;
    } 
    void show(){
        cout<<"x="<<x<<endl;
    }
};
class Derive:public Base{
private:
    int y;
    Base d;
public:
    Derive(int i,int j,int k):Base(i),d(j){
        y = k;
        cout<<"构造 derived 类, y="<<y<<endl;
    } 
    ~Derive(){
        cout<<"析构 derived 类, y="<<y<<endl;
    }
};
int main()
{
    Derive obj(1,2,3);
    obj.show();
    return 0;
}
如果派生类的基类也是派生类,则每个派生类只需要负责其直接基类的构造,即只需要对父类负责

构造的时候先构造第一代再第二代最后第三代,析构的时候刚好相反

由于析构函数是不带参数的, 在派生类中是否需要定义析构函数与它所属的基类无关, 故基类的析构函数不会因为派生类没有定义析构函数而得不到执行, 它们各自是独立的
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值