前言
面向对象基本特征之二,很重要的部分.继承和多态没很明显的界限,常常综合使用.
引入
回想程序的思路:
面向过程:需求→函数;
面向对象:需求→类和对象→方法; 或者 需求→接口→类和对象→方法
不管怎样,编程都是在用数据变化实现预定逻辑.从这里可以看出, 接口和类相当于方法的容器.同一个类产生不同的对象,实现同样的逻辑.做了效果不一样同样的事.类里面包含了方法和属性,方法是表达逻辑的,那属性是做什么的呢?属性可以看作被"聚拢"的数据,为了方法的实现而存在.起初笔者把属性当成类的组成,而现在认为更科学的看法是:属性是为了被方法使用而存在的数据
从箭头的走向来看,面向对象编程,首先考虑的是接口和类的设计.然而从上述分析,也可以得到设计类的基本思路了:你想做什么事---方法;你用哪些数据来做 ---属性.两个加到一起,类就出来了.
继承的出现
假设程序员面对的需求发生了改变,原先设计的类需要做改动,应该怎样处理这样的局面呢?于是继承的机制出现了.是的,继承是面向对象设计的机制,也有其对应的场景---解决升级.
继承的结构
继承由基类(父类)和派生类(子类)构成的体系.
基类特点:
1>基类的属性和方法为所有派生类共有;
2>基类可能被覆盖(重写)的方法设置为虚方法,由派生类实际完成;虚方法可以定义,也可以不定义;定义的虚方法可以被派生类调用;
派生类特点:
1>使用基类的属性和方法; ---继承考虑公有继承和保护继承,私有继承和多重继承除外
2>可以增加属性,重写基类虚方法,形成新的逻辑.
继承的步骤
1>基类设置共有属性和方法,设置虚方法;
2>派生类依照需要添加新属性,重写虚方法;
3>生成派生类对象,并采用基类引用(或指针)指向该对象;
4>调用基类虚方法;
举例
基类:
class BaseType{
private:
int account;
string name;
public:
BaseType(int ac,const string & na):account(ac),name(na){}
virtual void Fun(){
cout<< "account is:" << account<<endl;
cout<< "name is:" << name<<endl;
}
}
派生类:
class ExtendType:public BaseType{
private:
string information;
public:
ExtendType(int ac,const string & na,const string & in):BaseType(ac,na),information(in){}
virtual void Fun(){
BaseType::Fun();
cout<< "information is:" << information<<endl;
}
}
使用:
BaseType & bt=ExtendType(10000,"zs","good");
bt.Fun();
继承的分析
继承的关键词之一:虚方法(实际上是属于"多态"的特征,但是面向对象的三大特征联系很紧密)
虚方法表达一种既确定又不确定的逻辑.他既可以被定义和使用,也可以被派生类重写.
基类像"父亲",派生类像"儿子",他们共同经营企业.
名义上是父亲接受委托---对外调用虚方法,实际由儿子完成工作---实现方法.
继承的关键词之二:增加
儿子可以使用父亲提供的所有资源(公有继承),也可以增加自己的资源进去.
接口和继承
Java和C++语法有一些区别,Java是单继承多实现,只有一个父类,实现多个接口.C++没有接口实现一说,可以有多个父类.接口的实现也是通过继承的方式来实行.笔者从Java转过来,干脆摒弃了复杂的多重继承.---题外话
从语法形式上可以区别出接口和基类继承.接口是以纯虚方法为核心,对外调用纯虚方法,对内由接口实现类(或者接口实现类继承树)来实现其方法,没有基本骨架(基类),灵活度更加大.基类继承树以虚方法为核心,有基本骨架(基类)存在,相对受限制一些.
还有一点:接口可以容纳任意类. 如果设计不是从接口开始,那么可以对现成的类进行包络.这一点也提供了更大的自由设计空间.想象这种场景:不管何时何地,面对多么糟糕的前期设计,程序员想添加什么功能,直接定义个接口就可以整合,这无疑是很令人兴奋的.
但并不是说设计架构随便来.如果太复杂了还不如推到重来.程序架构是相当重要的.
白话继承
代码需要升级吗?首先考虑继承.
代码可能要改变吗?考虑用虚方法.