C++类的继承性

1、类中的成员函数和成员变量有三种属性:

private,    //私有成员,只能由类内部成员访问  //(默认属性)    //也是类封装性的体现

public,     //共有成员,类内成员或类对象、派生类都能访问

protected  //保护成员,类内成员或者派生类访问。

一般使用方式:类成员变量使用private;类成员函数使用public;而protected是在类继承中才会使用。(不继承的话,protected相当于private,也就是说,有些私有成员我们平时是当成私有成员,当有子类的时候,我们想让子类继承。)

2、类继承的方式有三种:

类可以是单继承(继承于一个父类)和多继承 (继承于多个父类)   

三种继承方式与成员属性相同,

public,//公有继承

private//私有继承

protected//保护继承

子类继承方式父类成员属性

继承结果及父类成员

在子类中属性

备注
publicpublic

子类可以访问,

属性仍为public

publicprivate

子类不可以访问

属性仍为private

publicprotected

子类可以访问,

属性仍为protected

这个就是protected

属性的意义

privatepublic

子类可以访问

属性变为private

privateprivate

子类不可以访问

属性仍为private

privateprotected

子类可以访问

属性变为private

protectedpublic

子类可以访问

属性变为protected

protectedprivate

子类不可以访问

属性仍为private

protectedprotected

子类可以访问

属性仍为protected

 说明:

1)我们一般使用的是public继承,其他两种继承方式可以暂时不管。

2)父类成员属性为private的,子类无论以何种方式继承,都无法访问的。

3)父类成员被子类继承后的属性,此时的属性可用性就可以参照1中的情况来分析了。

3、语法形式

类声明中如下形式

class  A : public class B

{

};

4、继承性特点

1)子类继承了除父类的构造函数、析构函数外的所有成员变量和成员函数;

2)子类可以拥有新的成员变量和成员函数。

3)父类成员函数为virtual时,子类可以重写该函数

4)父类成员函数不为virtual时,子类重新定义该函数时,会覆盖父类函数。

5、子类重写父类函数//父类成员函数声明的前面 添加virtual

父类成员函数为virtual时,子类可以重写该函数,注意函数名,参数必须完全一样否则即便是父类成员函数前有virtual也没用,不是重写,变成重定义了。

虚方法只有在使用指针或引用来调用函数的时候才会用到(指针/引用是基类指针/引用)

用对象来调用函数的时候,不会用到虚方法。

基类方法的声明中使用virtual可使该方法在基类及所有派生类(包括从派生类派生出的类)中是虚的。

重写函数的访问修饰符可以不同。即,假使virtual是private的,派生类中重写改写为public,protected也是可以的

假使方法是通过引用类型或指针类型选择方法:

1)当父类成员函数不是virtual时,程序会根据引用或指针类型来选择方法版本。

2)当父类成员函数前面有vitual, 程序将根据引用或指针指向的对象的类型来选择方法。

class CBase {
private:
    virtual void width() { //do sth.}
    
public:
    void length(string str) { //do sth. }
    void length(int num) { //do sth.} 
};

class CDerive:public CBase{
public:
    void width() { //do sth. }                 //重写,因基类中width()为虚函数
    void lenth(int num){//do sth.}            //重定义,lenth函数在父类中不为虚函数
    void length(int a,int b) { //do sth. }     //重定义,lenth函数在父类中不为虚函数
   
};

int main(){
    //非虚函数看指针/引用
    CBase fa;
    CDerive so;
    CBase &b1_ref = fa;
    CBase &b2_ref = so;
    b1_ref.length(1);    //use CBase::length();
    b2_ref.length(1);    //use CBase::length();

    //虚函数看指针/引用对象
    CBase *b3_ref = new CBase;
    CBase *b4_ref = new CDerive;
    b3_ref->width();    //use CBase::width();
    b4_ref->width();    //use CDerive::width();

}

6、子类重定义父类函数//一般不这么用//可以忽略不看

重定义 (redefining)也叫做隐藏:子类重新定义父类中有相同名称的非虚函数 ( 参数列表可以不同 ) 。

如果一个类,存在和父类相同的函数,那么,这个类将会覆盖其父类的方法,除非你在调用的时候,强制转换为父类类型,否则试图对子类和父类做类似重载的调用是不能成功的。

7、父类指针/引用 指向子类对象

该指针只能访问父类定义的函数,(静态联编)(与父类指针,指向父类对象一样的效果)

这是我们经常用到的,这也是虚函数的作用所在。即多态性的体现。同一个类中,函数名相同,函数参数不同,构成多态;基类继承类中,函数名、函数参数完全相同,通过基类指针指向的对象不同,也实现了多态性。

//同时将不同的数据类型放在一个数组是不可能的(比如将CBase和CDerive对象放在一起是不行的,
但是,可以将CBase*指针放在同一数组内,)
int main()
{
    CBase fa;
    CDerive so;
    CBase *pt[2]={&fa,&so};
    for(int i =0;i<2;i++)
    {
        pt[i]->width();
    }
}

 下图中展示了为什么基类指针/引用可以指向派生类对象的情况,而反之不行(除非显示强制转换)

8、子类指针指向父类对象//一般不这么定义//可以忽略不看

需要先进行强制类型转换(explicit cast);

9、析构函数为虚函数

10、小结:

1)将派生类引用或指针转换为基类引用或指针称为向上强制转换,这个不需要强制转换;派生类对象都是基类对象,继承了基类的所有数据成员和成员函数,所以对基类对象的任何操作,都适用于派生类对象。

2)相反的过程,将基类指针或医用转换为派生类指针或引用称为向下强制转换,如果不使用显示类型转换,向下强制转换是不允许的。

3)按值进行传递,只能将派生类中的基类部分传到函数中

11、总结

一般用法:

1)基类中需要继承类重写的函数前面应添加virtual

2)基类中析构函数前添加virtual

3)使用基类指针或引用指向基类对象或派生类对象实现动态连编

4)派生类直接值传递给基类,仍然调用的是基类的函数,是静态连编。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值