您的位置:首页 > 其它

虚函数、纯虚函数、抽象类、抽象方法和接口

2015-02-15 14:44 197 查看
首先讲下自己最近的电话面试遇到的相关问题。1、多态的两种实现方式?2、虚函数与纯虚函数的区别,如何使用这两种方式?3、接口和抽象类的关系?由这两个问题开始深入的理解一下虚函数,纯虚函数以及抽象类和接口之间的关系。

虚函数

百度定义:简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。

定义形式:virtual {method body} eg. virtual AnimalEat(){ }.

纯虚函数

百度定义:虚函数是一种特殊的虚函数,在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。

定义形式:

class <类名>

{

virtual <类型><函数名>(<参数表>)=0;

//virtual void AnimalEat()=0;



};

虚函数和纯虚函数区别(第一个问题解答)

1.对于虚函数来讲,父类和子类都有各自的版本。由动态方式调用的时候动态绑定。

2.在虚函数和纯虚函数的定义中不能有static标识符,原因很简单,被static修饰的函数在编译时要求前期bind,然而虚函数却是动态绑定(run-time bind)。

3.实现了纯虚函数的子类,该纯虚函数在子类中就变成了虚函数,子类的子类即孙子类可以覆盖该虚函数,由多态方式调用的时候动态绑定。

4.如果一个类中含有纯虚函数,那么任何试图对该类进行实例化的语句都将导致错误的产生,因为抽象基类(Abstract Base Class)是不能被直接调用的。必须被子类继承重载后,根据要求调用其子类的方法。

5.虚函数必须实现(必须要有函数体),如果没有实现,编译器将会报错,错误提示: unresolved external symbol “public: virtual void __thiscall

ClassName::virtualFunctionName(void)”。

6.虚函数可以被直接使用,也可以被子类重载以后以多态的形式调用,而纯虚函数必须在子类中实现该函数才可以使用,因为纯虚函数在基类中只有声明而没有定义。

7.虚函数和纯虚函数都可以在子类中被重载,以多态的形式被调用。

实例:

#include <iostream>
using namespace std;

class VirtualBaseClass
{
public:
virtual void Demo()=0;//pure abstract function
virtual void Base(){cout<<"This is the virtual base class!"<<endl;};
};

class SubVirtualClass : public VirtualBaseClass
{
public:
void Demo(){cout << "This is the pure abstract function implemented in subClass"<<endl;};
void Base(){cout << "this is the subclass of Base overwrite the father method Base()"<<endl;};

};

void main()
{
VirtualBaseClass* inst = new SubVirtualClass(); // multistate pointer

inst->Demo();
inst->Base();
return;
}

[程序输出结果:Vs008下亲测](http://img.blog.csdn.net/20150215124134948)


小结 1:

实现了纯虚函数的子类,该纯虚函数在子类中就成为了虚函数。—>>> 虚函数必须实现,如果不实现,编译器就会报错。—–>>>虚函数可以被直接使用,也可以被子类(sub class)重载以后以多态的形式调用。

虚函数是C++中实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。

C++中多态的实现通过两种机制:编译时多态性–>>通过重载函数实现;运行时多态性–>>通过虚函数实现。

http://blog.csdn.net/wuchuanpingstone/article/details/6742465

这篇文章分析了虚函数的底层实现,有心人士可以看看。

抽象类(Abstract class)

百科定义:通常在编程语句中用 abstract 修饰的类是抽象类。在C++中,含有纯虚函数的类称为抽象类,它不能生成对象;在java中,含有抽象方法的类称为抽象类,同样不能生成对象。而只含有虚函数的类(class)不能称为抽象类。

抽象类是为继承而存在的。

重要点:

抽象类可以包括抽象方法(普通类不能),同时也能包括普通的方法。

抽象方法智能声明在抽象类中,且不包含任何实现,派生类必须覆盖他们。

抽象类可以派生自一个抽象类,可以覆盖基类的抽象方法也可以不覆盖,如果不覆盖,则其派生类必须覆盖它们。

虽然不能定义抽象类的实例,但是可以定义它的指针,这正是用抽象类实现接口的重点所在。

抽象方法

抽象方法故名思意是对类中方法的抽象,通过abstract来修饰,通过override在子类里重载。抽象方法只允许在抽象类中进行方法的声明,继承一个抽象类的的子类,必须实现这个抽象类中所有抽象方法的重载,不然这个子类就不能被实例化,子类还是抽象类。

如下例子:

public abstract class myclass
{
public abstract int myint();

};

public class myclass1 : myclass
{
public override int myint()
{
cout<<"myint1()"<<endl;
}
public int myint2()
{
cout<<"myint2()"<<endl;
}
public int myint3()
{
cout<<"myint3()"<<endl;
}
public int myint4()
{
cout<<"myint3()"<<endl;
}

};


小结 2:通过上面的描述应该可以看出虚函数和抽象方法的区别和联系。抽象方法其实是隐式的virtual方法,但与virtual相比,它需要被强制进行重载且它只是声明,不含实现部分,抽象方法也不能被virtual修饰只能通过abstract修饰

接口

泛指实体把自己提供给外界的一种抽象化物,用以又内部操作分离出外部沟通方法,使其能被修改内部而不影响外界其他实体与其交互的方法。

接口: 接口是一个概念。它在C++中用抽象类来实现,在C#和Java中用interface来实现。

接口是引用类型的,类似于类,和抽象类的相似之处有三点:

1、不能实例化;

2、包含未实现的方法声明;

3、派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员(不仅是方法包括其他成员);

另外,接口有如下特性:

接口除了可以包含方法之外,还可以包含属性、索引器、事件,而且这些成员都被定义为公有的。除此之外,不能包含任何其他的成员,例如:常量、域、构造函数、析构函数、静态成员。一个类可以直接继承多个接口,但只能直接继承一个类(包括抽象类)。

小结 3:接口与抽象类的区别

抽象类可以包含非抽象方法和抽象方法。这里非抽象方法就是抽象类自己的成员。而接口里都是“抽象方法”,没有自己的成员

一个类可以继承自多个接口,但是只能继承一个类(包括抽象类)。

抽象类可以有字段。接口不能 接口也可以理解为一个纯抽象类的演变( 纯抽象类:一个抽象类里只有常量和public类型的方法的抽象类)。

1、类是对对象的抽象,可以把抽象类理解为把类当作对象,抽象成的类叫做抽象类.而接口只是一个行为的规范或规定,微软的自定义接口总是后带able字段,证明其是表述一类类“我能做。。。”抽象类更多的是定义在一系列紧密相关的类间,而接口大多数是关系疏松但都实现某一功能的类中.

2、接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法;

3、一个类一次可以实现若干个接口,但是只能扩展一个父类

4、接口可以用于支持回调,而继承并不具备这个特点。

5、抽象类不能被密封。

6、抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,当然您也可以声明为虚的。

7、(接口)与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上。

8、抽象类实现了oop中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义为不可变的,而把可变的作为子类去实现。

9、好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。

10、尽量避免使用继承来实现组建功能,而是使用黑箱复用,即对象组合。因为继承的层次增多,造成最直接的后果就是当你调用这个类群中某一类,就必须把他们全部加载到栈中!后果可想而知.(结合堆栈原理理解)。同时,有心的朋友可以留意到微软在构建一个类时,很多时候用到了对象组合的方法。比如asp.net中,Page类,有Server Request等属性,但其实他们都是某个类的对象。使用Page类的这个对象来调用另外的类的方法和属性,这个是非常基本的一个设计原则。

11、如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法。

总的来说,这部分东西比较多,有点乱,但是一定要抓住重点,才能不迷茫:

1。抽象函数和虚函数

抽象方法其实是隐式的virtual方法,但与virtual相比,它需要被强制进行重载且它只是声明,不含实现部分
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: