2 接口与继承
接口就是定义了一个统一的功能 功能的具体实现由对应的实现者实现
如你调用一个方法 就知道这个方法会返回什么结果 无论是哪个类的对象都一样 你不必知道调用的是什么类的方法
如你想调用一个画菜单接口 那么就知道调用它一定会在屏幕上画出菜单 而不论现在是在UNIX或是在WINDOWS上 也不必知道现在是使用什么库来实现
如果用过JAVA那就会知道JAVA中有INTERFACE方法 它定义了一个操作的接口 其它类想实现那个功能时可以使用impletes实现它的功能 在JAVA中事件的响应等都是这样实现的
在C++中 接口是使用抽象类来实现
继承是共享数据与代码的一个方法 用于在两个有ISA关系的类间
ISA就是 是一个 如笔记本电脑ISA(是一个) 电脑 那它就有电脑的属性与方法
但是它是笔记本 那会有自己的特征 这些特征就放在子类中实现 电脑的特征就在电脑类中实现 这样就不会要笔记本电脑中还实现电脑的功能 有重复的代码了
另外子类中有些方便会改变 这时子类需要定义自己的接口代替父类中同名接口
在C++中 想让子类接口代替父类接口应该把对应的接口定义为virtual
如下
CODE
#include <iostream>
using namespace std;
struct A{
void t(){
cout<<" A"<<endl;
}
virtual~A(){
cout<<" ~A"<<endl;
}
};
struct B:public A
{
virtual void t(){
cout<<" B"<<endl;
}
~B(){
cout<<" ~B"<<endl;
}
};
struct C:public B
{
void t(){
cout<<" C"<<endl;}
~C(){
cout<<" ~C"<<endl;
}
};
main(){
A a;
B b;
C c;
cout<<"first use A* to call t()"<<endl;
A*p=&a;
p->t();
p=&b;
p->t();
p=&c;
p->t();
cout<<"now use B* to call t()"<<endl;
B* v=&b;
v->t();
v=&c;
v->t();
cout<<"finally call destructor"<<endl;
return 0;
}
输出如下
CODE
first use A* to call t()
A
A
A
now use B* to call t()
B
C
finally call destructor
~C
~B
~A
~B
~A
~A
可以看到virtual从它定义的级别开始起作用
后面的析构是子类析构过程中调用父类析构
在继承中把析构函数定义成virtual的原因是
在使用父类指针指向子类时 处理完后可以正确的调用对应的析构函数
如下
CODE
#include <iostream>
using namespace std;
struct A{
void t(){
cout<<" A"<<endl;
}
~A(){
cout<<" ~A"<<endl;
}
};
struct B:public A
{
void t(){
cout<<" B"<<endl;
}
~B(){
cout<<" ~B"<<endl;
}
};
main(){
A*p= new B();
delete p;
return 0;
}
显示为
CODE
~A
第二次修改A中
~A(){
改成
virtual ~A(){
后
CODE
~B
~A
可以看到资源被正确释放
接口与继承的比较
接口中并没有实现代码 它只是说明这个接口会有什么功能 如何提供这个功能是实现这个接口的类的任务
继承中是子类继承代码 也就是子类共用父类的代码实现父类的功能
针对接口编程 而不是针对实现编程好处是
1 客户不必知道他们使用对象的特定类型 而只要对象有客户期望的接口
2 客户不必知道他们使用的对象是使用什么类来实现的 只须知道定义接口的抽象类
这样就减少了子系统实现间的依赖关系