面向对象编程的主要目的之一是提供可重用的代码,C++类提供了更高层次的重用性,比如类继承。类有三种继承方式,公用,私有,保护。这一章只讲公有继承。
派生一个类
使用公有派生,基类的公有成员将成为派生类的公有成员,基类的私有部分也将成为派生类的一部分,但只能通过基类的公有和保护方法访问。
- 派生类对象存储了基类的数据成员(派生类继承了基类的实现)
- 派生类对象可以使用基类的方法(派生类继承了基类的接口)
- 派生类需要自己的构造函数
- 派生类可以根据需要添加额外的数据成员和成员函数
构造函数
构造函数必须给新成员和继承的成员提供数据,但是派生类不能直接访问基类的私有成员,而必须通过基类方法进行访问,换句话说,要构造派生类,需要调用基类的构造函数。
- 首先创建基类对象
- 派生类构造函数应通过成员初始化列表将基类信息传递给基类构造函数
- 派生类构造函数应初始化派生类新增的数据成员
释放对象的顺序与创建对象的顺序相反,即首先执行派生类的析构函数,然后自动调用基类的析构函数。
指针
基类指针可以指向派生类对象,但相反却不可以。基类指针指向派生类对象是向上强制转换,而派生类指针指向基类对象是向下强制转换。如果是强制转换的话倒也可以编译,但是是有风险的。因为基类的方法派生类都有,但派生类的方法,基类不一定有。这是C++的一个保护手段。
也正是因为基类的指针和引用可以指向派生类,导致了,原来为基类准备的函数,派生类也可以调用。很符合代码的重用性。
多态公有继承
如果派生类想改变基类中已经存在的类方法,那么只需要再重新定义一个就好,但是这样出现了一个问题,因为基类指针是可以指向派生类的,那么如果指针或引用调用类方法的时候,默认是基类的类方法,尽管两个方法的实现不同,毕竟是基类指针,哪怕指向的是派生类函数。
为了解决这个问题,可以再基类的方法的声明前加上virtual,表示是虚方法,那么,当指针和引用调用方法的时候会判断到底是基类方法还是派生类方法。
如果重新定义基类方法时却需要调用基类方法肿么办?为了防止陷入递归死循环,应该使用作用域解析符。
还要注意,只要派生类重新定义了类方法,基类中的所有类方法都不能用了,包括基类中的函数重载。
因为基类可能使用动态内存,派生类也可能使用,因此,最好在基类中使用虚析构函数,保证派生类释放时正确。不是采用基类析构函数释放的。
访问控制:protected
protected和private的区别只有在基类派生的类中 才会表现出来。派生类的成员可以直接访问基类的保护成员,但不能直接访问基类的私有成员。因此,对于外部世界来书,保护成员的行为与私有成员相似;但对于派生类来说,保护成员的行为与公有成员相似。
最好对数据成员私有而不是保护,部分方法可以保护。
抽象基类
如果两个或多个类有共同点,而又有不同点,那么便可以声明一个只含有共同点的抽象基类,然后其他各个类都作为这个基类的派生,只添加不同点。
要声明抽象基类,需要让它包含纯虚函数,所谓纯虚函数,就是虚函数的声明后面加上个=0.
纯虚函数可以没有定义,但也可以有定义,他的定义只用在派生类没有定义的情况。纯虚函数用来定义派生类的通用接口。
抽象基类不被允许声明对象,只是作为一个基类使用,只要包含纯虚函数便被认为是抽象基类。
强制转换
我也不知道为什么把强制转换单独拿出来总结,感觉挺重要的,或者说挺容易错的。
因为基类和派生类的关系很微妙,派生类在一定程度上讲,对基类的方法挺兼容,但是对象友元函数,运算符重载等一些特殊情况,很容易照成二义性甚至是因为类型判断失误导致递归性的死循环,因此善用强制转换,尤其是在基类和派生类类型模糊的时候。多想想,多写点,累不死。^^