C++——Inherit && Derive

继承:实现了代码的可重用性

类的继承, 是新的类从已有类那里得到已有的特性。 或从已有类产生新类的过程就是类的派生。

原有的类称为基类或父类, 产生的新类称为派生类或子类。派生与继承, 是同一种意义两种称谓。

继承:Is  a 的关系 public;

语法:

1、单继承

Class Derive :public Base

{}

2、 多继承

Class Derive:public Base1,public Base2

{}

继承方式与访问权限

继承方式的public、pro、pri  和 子类及子类对象的访问权限public、pro、pri。

继承方式不影响子类成员的访问方式,影响父类成员在子类内的访问权限

访问:一是在子类内,二是在子类对象内

子类中的访问方式:public、protected、private、inaccess(不可见)

 

  • public 传承接口 间接的传承了数据(protected)。
  • protected 传承数据,间接封杀了对外接口(public)。
  • private 统杀了数据和接口。

 

派生类(子类)

构造器

  1. 初始化顺序的问题:先祖祖祖祖父,后类对象的构造器,最后子类的构造器。析构顺序与此相反,先子类 再类对象 再父类
  2. 存在两代以上的构造器,Student派生Graduate,Gra派生Doctor

构造的时候只与父类相关(两代之间解决,不涉及祖类

***注意赋值方式(因为有私有成员存在,其他方式不可访问)

拷贝构造

1、基类拷贝构造

浅拷贝:等位拷贝,相同的成员进行赋值即可(系统自实现)

2、派生类拷贝构造   ***注意赋值方式***

赋值运算符重载

1、基类

基类 即 简单运算符重载

2、派生类

(1)一是父类的属性的重载,直接用

operator = (another) 重名了,加上作用于Student::

(2) 不能采用  :提前赋值 构造 (原来已有了再构造à深拷贝导致内存泄漏)

类的作用域运算

shadow现象

父类和子类的成员函数重名了,(eg:父类和子类都有 void display () )那么子类成员会将父类成员shadow掉。

这时就需要 基类名+作用域运算符 的方式才能调用基类的同名成员

注意:

重载 overload  :同一个作用域 函数名相同 参数列表不同(参数类型、数量、顺序)
shadow            :存在于父子类中,只要函数名相同,即可构成shadow(只看名字)

派生类中的友元

由于友元函数并非类成员,因引不能被继承,在某种需求下,可能希望派生类的友元函数能够使用基类中的友元函数。为此可以通过强制类型转换,将派生类的指针或是引用强转为其父类的引用或是指针,然后使用转换后的引用或是指针来调用基类中的友元函数。(满足了子类继承父类的成员函数的需求)

******强转******

#include <iostream>
using namespace std;

class Student
{
    friend ostream &operator<<(ostream & out, Student & stu);//重载<<
private:
    int a;
    int b;
};

ostream &operator<<(ostream & out, Student& stu)//Student的重载实现
{
    out<<stu.a<<"--"<<stu.b<<endl;
}

class Graduate:public Student
{
    friend ostream &operator<<(ostream & out, Graduate & gra);
private:
    int c;
    int d;
};
//派生类中的友元函数可以使用几类中的友元函数(强转)?
//将派生类的指针或是引用强转为其父类的引用或是指针,然后使用转换后的引用或是指针来调用基类中的友元函数。
ostream &operator<<(ostream & out, Graduate & gra)
{
//  out<<(Student&)gra<<endl;//继承下来的数据的cout调用父类的cout
    out<<static_cast<Student&>(gra);//Student& 类型不可变 与Student不同!!!
    out<<gra.c<<"**"<<gra.d<<endl;
}

int main()
{
    // Student a;
    // cout<<a<<endl;
    Graduate g;
    cout<<g<<endl;
    return 0;
}


 

析构

~~~(1)析构顺序  与构造相反

~~~(2)自己做好自己的事,同级之间析构。子类不用管父类的析构。。

多继承

子类和父类成员重名的时候。子类中的operator = shadow了父类中的operator = 。在子类中只能调用子类的operator =;在完成子类的赋值重载时,不要直接调用operator = ;

可用:   父类::operator =    ……(加个前缀 命名空间~)

多继承出现了数据冗余,调用不便。

要解决的问题: 一是实现派生类的数据只有一份。二是数据访问遍历。

 

多继承之——虚继承

在上述多继承中,多个父类 保留多份数据成员的拷贝, 不仅造成数据冗余,占有较多的存储空间; 还增加了子类及其对象访问的难度。

为此,C++提供一多基类与多继承的机制,实现了在多继承中保存一份数据。(提取父类中的公共成员,统一存储,方便访问)

(1)虚基类:建立一个新(祖父)类来存储多个父类中的共有元素。

(2)虚继承:继承的扩展,解决菱形继承的二义性问题(两个父类中都有,到底访问谁的-->作用域::)

初始化顺序:祖父类-->父类-->子类。

 
virtual public
(1)解决从父类继承的时候,会有重复的属性造成的数据冗余。
(2)虚继承实现了数据存储一份,但子类可以实现数据遍历。

注意:
(1)使用时父类和祖父类之间用virtual。

         子类和父类之间不需虚继承。子类构造的时候需要写入两个父类和祖父类的数据进行构造。

虚继承示例:沙发床(子类)+床、沙发(父类)+描述两者特点(祖父类)

//Headers

//(1)grandfather (祖父类)
class grandfather
{
public:
    grandfather(float l,float wi,float we);
    void dis();
protected:
    float len;
    float wid;
    float weight;
};

//(2)bed.h
class Bed:virtual public grandfather  //注意是虚继承
{
public:
    Bed(float l,float wi,float we);
    void sleep();
};
//(3)sofa.h
class Sofa:virtual public grandfather
{
public:
    Sofa(float l,float wi,float we);
    void sofa ();
};

//(4)sofabed (子类)
class SofaBed:public Sofa,public Bed
{
public:
    SofaBed(float l,float wi,float we);
};


//cpp文件

//(1)grandfather.cpp

#include "grandfather.h"
#include <iostream>
using namespace  std;

grandfather::grandfather(float l, float wi, float we)
 :len(l),wid(wi),weight(we)
{
}
void grandfather::dis()
{
    cout<<"len     = "<<len<<endl;
    cout<<"wid     = "<<wid<<endl;
    cout<<"weight  = "<<weight<<endl;
}

//(2)sofa.cpp
#include "sofa.h"

Sofa::Sofa(float l, float wi, float we)
    :grandfather(l,wi,we)
{
}
void Sofa::sofa ()
{
    cout<<"i am having fun!"<<endl;
}

//(3)bed.cpp
#include "bed.h"
#include<iostream>
using namespace std;

Bed::Bed(float l, float wi, float we)
    :grandfather(l,wi,we)
{
}
void Bed::sleep()
{
    cout<<"i am sleeping!"<<endl;
}
//(4)sofabed.cpp
#include "sofabed.h"

SofaBed::SofaBed(float l,float wi,float we)
    :Bed(l,wi,we),Sofa(l,wi,we),grandfather(l,wi,we) //*****父类、祖父类都要写
{
}


//main

#include <iostream>
#include "sofabed.h"
#include "bed.h"
#include "sofa.h"
#include "grandfather.h"
using namespace std;

int main()
{
    Bed b(1,2,3);
    b.dis();
    cout<<"-------------"<<endl;
    SofaBed sb(3,4,5);
    sb.dis();
    cout<<"-------------"<<endl;
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值