继承

继承实例如下:

class Super
{
public:
    Super();
    void someMethod();
protected:
    int mProtectedInt;
private:
    int mPrivateInt;    
};

class sub:public Super
{
public:
    Sub();
    void someOtherMethod();
};
(1)派生类sub可以访问基类的public和protected成员

(好的做法是 ,将所有的数据成员都定义为private成员,如果希望所有的代码都能获得其访问权限,就在public中加入获取和设置的方法,如果只允许派生类访问,就在protected中加入获取和设置该值的方法)

(2)final 关键字可以禁用继承 :class Super final {...};

  final 还可以用于禁用重写:virtual void someMethod() final; 

(3)一旦一个方法或者析构函数标记为virtual(表示调用时要进行动态绑定,可以不覆盖直接使用,可以在进行覆盖的时候末尾加关键字override(声明的时候加,定义的时候不加)),那么所有派生类中都是virtual,即使不加关键字;使用override可以防止错误重写,因为不加该关键字,如果重写错误会创建一个新的虚方法,并不报错;但是加了该关键字表明该方法就是在重写,如果重写错误会报错。

(4)继承类的创建顺序:先执行基类的默认构造函数,再按声明顺序创建,继承类的非静态数据成员,最后执行该继承类的构造函数;

析构函数的调用顺序:先调用继承类的析构函数,再销毁继承类的数据成员(后声明的先销毁,与创建顺序相反,最后调用父类的析构函数)

(5)在调用当前方法的父类版本的时候,一定要加上作用域解析运算符,否则会无限递归当前版本;

(6)纯虚方法,virtual void func(...) =0   

定义了纯虚方法的类都是抽象类,无法构造该类的对象(但可以构造抽象类指针,因为它可以指向派生类)

如果派生类没有实现从抽象类继承的纯虚方法,该派生类也是抽象的;

(7)多重继承的时候,如果多个父类有相同名字的方法,进行调用的时候可以在前面加上作用域解析符:

class1.parent1::method();

或者使用using parent1::method;进行显式指定;

(using关键字可以用于包含基类定义的各种方法,包括构造函数)

(8)重写:

修改方法的返回类型:(协变返回类型)不能将返回类型修改为完全不相关的类型,比如:基类方法中返回的是基类的指针或引用,在派生类里面重写方法的时候,可以将返回类型修改为派生类的指针或引用;

如果派生类方法中参数有一点不同,那么就不是重写而是重新定义了一种新的虚方法;

(9)不能重写静态方法(一般需要重写的方法设置为虚方法,而一个方法不可能是静态的又是虚的,意义上矛盾)

(10)为了避免歧义,应答重写基类重载方法的所有版本,可以显示重写,也可以用using,但using关键字只能指定方法名没有参数,所以使用后表示用了父类的所有版本,有一定风险!

(11)虽然派生类不能访问基类的private方法,但是可以重写private方法(限C++,java和C#不能)

(12)试图重写基类的非虚方法将“隐藏”基类定义的方法,这个方法只能在派生类环境中使用;

(13)基类指针引用指向派生类对象时,只能调用基类函数的成员函数,以及派生类的虚函数重写版本;

(14)虚函数的内部实现(重写必须使用virtual)

每个具有一个或者多个虚方法的类都有一张虚表,该类的每个对象都包含指向虚表的指针;虚表包含指向虚方法实现函数的指针(重写后指向重写后的版本实现函数);(java中每个方法都自动为virtual);

虚指针是每个对象都有,虚表是类共享。继承自几个基类就有几个虚指针指向几个虚表

子类自己的虚函数也会放在虚函数表中。

考虑:多重继承时,子类自己的虚函数应当怎么存放?

一般是存放在第一个基类对应的虚函数表中,该基类也称作主基类


此时,B为D的主基类,D的虚函数qux()与B的虚函数共存


(15)非public继承,不常见。protect继承将父类所有public方法和数据成员定义为protect,private也是类似;

(16)构造函数不能声明为虚函数:虚函数在运行时确定类型,执行构造函数的时候,对象还没有创造成功,无法知道类型;

   析构函数最好声明为虚函数:如果有一个基类指针指向派生类对象,调用析构函数时,如果不是虚函数则只删除基类部分,造成内存泄漏;(至于动态绑定调用派生类的析构函数后,编译器会自动调用执行基类的析构函数)

(17)向上转型:派生类对象转型成基类

如果直接使用赋值,会产生截断,派生类中的部分没了:

parent mychildren = children;

但是使用基类引用或是指针不会产生截断:

parent& mychildren=children;

parent* mychildren =children;

向下转型:基类转换成其派生类(不好),使用dynamic_cast;

(18)父类指针指向子类实例对象,调用普通重写函数时,会调用父类中的函数。而调用被子类重写虚函数时,会调用子类中的函数。因为虚函数是动态绑定的

(19)子类继承父类大部分的资源,不能继承的有构造函数,析构函数,拷贝构造函数,operator=函数,友元函数

(20)继承和组合

组合指的是新的类中包含多个其他类的对象。

继承和组合关系的选择:当需要从现有的对象向上回溯到之前的对象时,采用继承;is a用继承,hava a用组合

(21)菱形继承


造成的后果是数据的冗余,会报错。调用base中的函数的时候,会出现调用不明确错误。

解决方式:试用父类作用域的限定符,限定调用的是哪一个父类的基类部分(即A的Base还是B的Base)

还可以使用虚继承的方式:class A:public virtual Base{...};class B:public virtual Base{...};

采用这种虚继承的方式,则A和B共享Base中的内容,内部指针保存的不再是一个完整的Base,而是偏移量(指向一个公共地址,改地址保存的是Base的内容)

(22)在执行构造和析构的过程中,不要调用virtual函数,因为不会动态绑定到子类(有可能子类还没有构造出来)


(23)重写有可能掩盖重载



Derived d;

d.mf1(1); //会出错,mf1()重写会覆盖基类的重载函数


解决方法:

在Derived中using Base::mf1;

   using Base::mf3;

  然后在进行重写,这个时候就可以使用了。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值