一个纯虚函数的声明总是以=0结束声明中最后二个字符是

在虚函数的声明的参数列表之后加上“=0”就将函数变成了纯虚函数
& 虚函数:在虚函数的声明的参数列表之后加上&=0&就将函数变成了纯虚函数,如:
class& Base&
&&& virtual void function()=0;&
class& Base
&&& virtual void function()=0;
}我们不需要为纯虚函数Base::function()提供任何定义,那些声明了纯虚函数的类就是抽象类。任何试图创建一个抽象类对象的操作都会导致编译器错误。
如果一个类派生子Base并且重写了Base::function()函数,它就成为了具体的类了。
class Derived :public Basae&
& void function();&
class Derived :public Basae
& void function();
我们通常将抽象类用作接口声明,这时我们不需要为该接口声明一个完整的实现,该接口描述了所有派生自该类的对象都应该支持的操作;派生类必须实现这些抽象操作。
class& Base&
&&& public:&
&&&&&&& virtual void print()=0;&
class Derived :public Base&
&&& public:&
&&&&&&& virtual void print()&
&&&&&&& {&
&&&&&&&&&&& cout&&&Derived::Derived()\n&;&
&&&&&&& }&
&&&&&&& ~Derived()&
&&&&&&& {&
&&&&&&&&&&& print();&
&&&&&&& }&
int main()&
&&& Derived D;&
&&& Base* ptr=&D;&
&&& D.print();&
class& Base
&&& public:
&&&&&&& virtual void print()=0;
class Derived :public Base
&&& public:
&&&&&&& virtual void print()
&&&&&&&&&&& cout&&&Derived::Derived()\n&;
&&&&&&& ~Derived()
&&&&&&&&&&& print();
int main()
&&& Derived D;
&&& Base* ptr=&D;
&&& D.print();
}运行结果:
Derived::Derived()
Derived::Derived()
第一个Derived::Derived()是通过D直接调用print()时所产生的输出,第二个是在程序结束时调用~Derived()时产生的输出。
虽然我们不可以直接创建抽象类的对象了,但是仍然可以使用指向Base的指针和引用。
比如: Base* ptr= &D;当前位置: →
→ 虚函数与纯虚函数
虚函数与纯虚函数
& 作者及来源: 思禽 - 博客园 &
&收藏到→_→:
摘要: 虚函数与纯虚函数
"虚函数与纯虚函数"::
1、基本形式:virtual
function()
  ......}
function() = 0;
class animail{public:
function()
    cout && "animail::function()" &&
class dog: public animail{public:
function()
    cout && "dog::function()" &&
main(int argc, char *argv[]){
  animail
*p =//定义父类的指针
  p = &m; //父类指针指向子类对象
  p-&function();
  p-&function();
  return 0;}
这段代码的输出结果是什么呢?起初我认为是:animail::function()与dog::function(),因为第一次输出是引用基类animail的实例,第二次输出是引用子类dog的实例。
事实上答案是animail::function()与animail::function(),为什么呢?
这里我们需要明白:不管引用的实例是哪个类的,当你调用的时候,系统会调用左值那个对象所属类的方法。
比如说上面的代码类animail 和dog都有一个function函数,因为p是一个animail类的指针,所以不管你将p指针指向类animail或是类dog,最终调用的函数都是类animail的function函数。
这就是静态联篇,在编译的时候就已经确定好了。可是如果我想实现跟据实例的不同来动态决定调用哪个函数呢?这就须要用到(也就是动态联篇)。
animail{public:
  virtual
function()
    cout && "animail::function()" &&
classdog : public animail{public:
  virtual
function()
    cout && "dog::function()" &&
在基类的成员函数前加关键字virtual,则表示这个函数是一个。
所谓就是在编译的时候不确定要调用哪个函数,而是动态决定将要调用哪个函数,这样的话,就可以使用后期绑定来达到多态了,也就是:用基类指针调用子类的这个函数。
要实现必须保证派生类中的函数名与基类中的相同,参数名、参数类型等也要与基类一致。但派生类中的virtual关键字可以省略,也表示这是一个。
下面来分析一下代码,声明一个基类的指针(必须是基类,反之则不行)p,把p指向类animail的实例canimail,调用function函数,这时系统会判断p所指向的对象的类型,如果是animail类的对象就调用animail类的function函数,如果是dog类的对象就调用dog类的function函数。
下面来讲一下纯,包含纯的类也可叫虚基类或者抽象类:
animail{ public:
  virtual
get_color() = 0;};
class dog: public animail{ public:
  virtual
get_color()
    cout &&
pig: public animail{public:
  virtual void get_color()
    cout && "white" &&
如上代码,定义了一个动物类(animail),类中有一函数getcolor可取得动物颜色,但动物有很多很多种,颜色自然无法确定,此文来自: 马开东博客
转载请注明出处 网址:
所以就把它声明为纯,也就是光声明函数名不去定义(实现)它,类dog继承了animail并实现了里面的代码,返回黄色。pig类同样道理。有一点须要注意一下,纯不能实例化,但可以声明指针,所以上面的main函数中: 会告诉你:由于它的成员的原因,无法instantiate抽象类animail,并且警告你get_color() 没有定义。
1. 是非静态的、非内联的成员函数。
2. 若类中一个成员函数被说明为,则该成员函数在派生类中可能有不同的实现。当使用该成员函数操作指针或引用所标识的对象时,对该成员函数调用可采用动态联编。
3. 定义了后,程序中声明的指向基类的指针就可以指向其派生类。在执行过程中,该函数可以不断改变它所指向的对象,调用不同版本的成员函数,而且这些动作都是在运行时动态实现的。充分体现了的动态多态性。充分体现了的动态多态性。
1. 在c++中,含有纯的类称为抽象类,它不能生成对象。抽象类是不完整的,并且它只能用作基类。抽象类不能直接实例化,并且对抽象类使用 new 运算符在编译时报错。
2. 当在基类中不能为给出一个有意义的实现时,可以将其声明为纯,其实现留给该基类的派生类完成。
3. 纯的作用是为派生类提供一个一致的接口,它只是个函数的声明而已,它告诉,在这个类中的这个纯是没有函数定义的,该类不能创建对象(即不能实例化),但可以声明指针,该类的派生类负责给出这个纯的重载定义。搜索此文相关文章:与纯此文来自: 马开东博客
网址: 站长QQ
虚函数与纯虚函数_博客园相关文章
博客园_总排行榜
博客园_最新
博客园_月排行榜
博客园_周排行榜
博客园_日排行榜欢迎加入我们,一同切磋技术 &
用户名: &&&
密 码: &
共有 4915 人关注过本帖
标题:C++多态性基本概念 包括虚函数和纯虚函数
等 级:新手上路
帖 子:36
结帖率:66.67%
&&问题点数:0&&回复次数:24&&&
C++多态性基本概念 包括虚函数和纯虚函数
C++编程语言是一款应用广泛,支持多种程序设计的计算机编程语言。我们今天就会为大家详细介绍其中C++多态性的一些基本知识,以方便大家在学习过程中对此能够有一个充分的掌握。
  前几天笔试的时候碰到考C++多态性的题目,因为不是自己的专业不是纯做软件开发,C++学习不是很好,做得有点混乱。回来以后立刻查了相关资料,大概明白了一点,可能以后解题的时候不会乱了。
  先摘下一些网上的书上的基本概念。
  多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。多态(polymorphisn),字面意思多种形状。
  C++多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖(override),或者称为重写。(这里我觉得要补充,重写的话可以有两种,直接重写成员函数和重写虚函数,只有重写了虚函数的才能算作是体现了C++多态性)而重载则是允许有多个同名的函数,而这些函数的参数列表不同,允许参数个数不同,参数类型不同,或者两者都不同。编译器会根据这些函数的不同列表,将同名的函数的名称做修饰,从而生成一些不同名称的预处理函数,来实现同名函数调用时的重载问题。但这并没有体现多态性。
  多态与非多态的实质区别就是函数地址是早绑定还是晚绑定。如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。
  那么多态的作用是什么呢,封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。也就是说,不论传递过来的究竟是那个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。
  最常见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。因为没有多态性,函数调用的地址将是一定的,而固定的地址将始终调用到同一个函数,这就无法实现一个接口,多种方法的目的了。
笔试的题目
#include &stdio.h&
&&& public:&&void foo()&&
&&&&&&&&printf(&1&);
&&& virtual void fuu()&&
&&&&&&&&printf(&2&);&&
class B:public A&&
&&& public:&&void foo()&&
&&&&&&&&printf(&3&);&&
&&& void fuu()&&
&&&&&&&&printf(&4&);&&
int main()
&&& A *p = &a;
&&& p-&foo();
&&& p-&fuu();&&
&&& p = &b;
&&& p-&foo();
&&& p-&fuu();
&&& return 0;
&&& 第一个p-&foo()和p-&fuu()都很好理解,本身是基类指针,指向的又是基类对象,调用的都是基类本身的函数,因此输出结果就是1、2。
  第二个输出结果就是1、4。p-&foo()和p-&fuu()则是基类指针指向子类对象,正式体现多态的用法,p-&foo()由于指针是个基类指针,指向是一个固定偏移量的函数,因此此时指向的就只能是基类的foo()函数的代码了,因此输出的结果还是1。而p-&fuu()指针是基类指针,指向的fuu是一个虚函数,由于每个虚函数都有一个虚函数列表,此时p调用fuu()并不是直接调用函数,而是通过虚函数列表找到相应的函数的地址,因此根据指向的对象不同,函数地址也将不同,这里将找到对应的子类的fuu()函数的地址,因此输出的结果也会是子类的结果4.
  笔试的题目中还有一个另类测试方法。即
  B *ptr = (B *)&a;&&ptr-&foo();&&ptr-&fuu();
  问这两调用的输出结果。这是一个用子类的指针去指向一个强制转换为子类地址的基类对象。结果,这两句调用的输出结果是3,2。
  并不是很理解这种用法,从原理上来解释,由于B是子类指针,虽然被赋予了基类对象地址,但是ptr-&foo()在调用的时候,由于地址偏移量固定,偏移量是子类对象的偏移量,于是即使在指向了一个基类对象的情况下,还是调用到了子类的函数,虽然可能从始到终都没有子类对象的实例化出现。
  而ptr-&fuu()的调用,可能还是因为C++多态性的原因,由于指向的是一个基类对象,通过虚函数列表的引用,找到了基类中foo()函数的地址,因此调用了基类的函数。由此可见多态性的强大,可以适应各种变化,不论指针是基类的还是子类的,都能找到正确的实现方法。
//小结:1.有virtual才可能发生多态现象2.不发生多态(无virtual)调用就按原类型调用
#include &iostream&
class Base
&&& public:
&&&&&&&&virtual void f(float x){ cout && &Base::f(float) & && x && }
&&&&&&&&void g(float x){ cout && &Base::g(float) & && x && }
&&&&&&&&void h(float x){ cout && &Base::h(float) & && x && }
class Derived : public Base
&&& public:
&&&&&&&&virtual void f(float x){ cout && &Derived::f(float) & && x && }//多态
&&&&&&&&void g(int x){ cout && &Derived::g(int) & && x && }//覆盖
&&&&&&&&void h(float x){ cout && &Derived::h(float) & && x && }//复制
void main(void)
&&& Base *pb = &d;
&&& Derived *pd = &d;
&&& // Good : behavior depends solely on type of the object
&&& pb-&f(3.14f); // Derived::f(float) 3.14
&&& pd-&f(3.14f); // Derived::f(float) 3.14
&&& // Bad : behavior depends on type of the pointer
&&& pb-&g(3.14f); // Base::g(float) 3.14
&&& pd-&g(3.14f); // Derived::g(int) 3 (surprise!)
&&& // Bad : behavior depends on type of the pointer
&&& pb-&h(3.14f); // Base::h(float) 3.14 (surprise!)
&&& pd-&h(3.14f); // Derived::h(float) 3.14
&&& system(&pause&);
//---------------------------------------------------------
C++纯虚函数
&&纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”
&&virtual void funtion1()=0
二、引入原因
&&1、为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。
&&2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
&&为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。
三、相似概念
&&1、多态性
&&指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C++支持两种多态性:编译时多态性,运行时多态性。
&&a.编译时多态性:通过重载函数实现
&&b 运行时多态性:通过虚函数实现。
&&2、虚函数
&&虚函数是在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态重载
&&3、抽象类
&&包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。
[编辑本段]
&&void f1();
&&virtual void f2();
&&virtual void f3()=0;
&&virtual ~A();
&&class B : public A
&&void f1();
&&void f2();
&&void f3();
&&virtual ~B();
&&int main(int argc, char* argv[])
&&A *m_j=new B();
&&m_j-&f1();
&&m_j-&f2();
&&m_j-&f3();
&&delete m_j;
&&return 0;
&&f1()是一个普通的重载.
&&调用m_j-&f1();会去调用A类中的f1(),它是在我们写好代码的时候就会定好的.
&&也就是根据它是由A类定义的,这样就调用这个类的函数.
&&f2()是虚函数.
&&调用m_j-&f2();会调用m_j中到底保存的对象中,对应的这个函数.这是由于new的B对象.
&&f3()与f2()一样,只是在基类中不需要写函数实现.
虚函数和纯虚函数
在面向对象的C++语言中,虚函数(virtual function)是一个非常重要的概念。因为它充分体现了面向对象思想中的继承和多态性这两大特性,在C++语言里应用极广。比如在微软的MFC类库中,你会发现很多函数都有virtual关键字,也就是说,它们都是虚函数。难怪有人甚至称虚函数是C++语言的精髓。
那么,什么是虚函数呢,我们先来看看微软的解释:
虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。
——摘自MSDN
这个定义说得不是很明白。MSDN中还给出了一个例子,但是它的例子也并不能很好的说明问题。我们自己编写这样一个例子:
#include &stdio.h&
#include &conio.h&
class Parent
char data[20];
void Function1();
virtual void Function2(); // 这里声明Function2是虚函数
void Parent::Function1()
printf(&This is parent,function1\n&);
void Parent::Function2()
printf(&This is parent,function2\n&);
class Child:public Parent
void Function1();
void Function2();
void Child::Function1()
printf(&This is child,function1\n&);
void Child::Function2()
printf(&This is child,function2\n&);
int main(int argc, char* argv[])
Parent *p; // 定义一个基类指针
if(_getch()=='c') // 如果输入一个小写字母c
p=& // 指向继承类对象
p=& // 否则指向基类对象
p-&Function1(); // 这里在编译时会直接给出Parent::Function1()的
入口地址。
p-&Function2(); // 注意这里,执行的是哪一个Function2?
用任意版本的Visual C++或Borland C++编译并运行,输入一个小写字母c,得到下面的结果:
This is parent,function1
This is child,function2
为什么会有第一行的结果呢?因为我们是用一个Parent类的指针调用函数Fuction1(),虽然实际上这个指针指向的是Child类的对象,但编译器无法知道这一事实(直到运行的时候,程序才可以根据用户的输入判断出指针指向的对象),它只能按照调用Parent类的函数来理解并编译,所以我们看到了第一行的结果。
那么第二行的结果又是怎么回事呢?我们注意到,Function2()函数在基类中被virtual关键字修饰,也就是说,它是一个虚函数。虚函数最关键的特点是“动态联编”,它可以在运行时判断指针指向的对象,并自动调用相应的函数。如果我们在运行上面的程序时任意输入一个非c的字符,结果如下:
This is parent,function1
This is parent,function2
请注意看第二行,它的结果出现了变化。程序中仅仅调用了一个Function2()函数,却可以根据用户的输入自动决定到底调用基类中的Function2还是继承类中的Function2,这就是虚函数的作用。我们知道,在MFC中,很多类都是需要你继承的,它们的成员函数很多都要重载,比如编写MFC应用程序最常用的CView::OnDraw(CDC*)函数,就必须重载使用。把它定义为虚函数(实际上,在MFC中OnDraw不仅是虚函数,还是纯虚函数),可以保证时刻调用的是用户自己编写的OnDraw。虚函数的重要用途在这里可见一斑。
再看下面的
-----------------------------------------------------------
摘自:C++中虚函数和纯虚函数的概念,差别和分别存在的原因
首先:强调一个概念
定义一个函数为虚函数,不代表函数为不被实现的函数
定义他为虚函数是为了允许用基类的指针来调用子类的这个函数
定义一个函数为纯虚函数,才代表函数没有被实现
定义他是为了实现一个接口,起到一个规范的作用,规范继承这个
类的程序员必须实现这个函数。
对继承的影响:
普通的类(没有虚函数,纯虚函数)就可以被继承,而且工作的相当好
关于这个问题有以下疑问:
纯虚函数难道就是为了实现接口?接口存在的意义?
我实在弄不懂,我干嘛要预先定义好?未来的事情本难料
就等有一天我的类中需要使用某个函数,在添加一个函数
不久可以?
关于实例化一个类:
有纯虚函数的类是不可能生成类对象的,如果没有纯虚函数则可以。比如:
virtual void fun() = 0; // 说明fun函数为纯虚函数
virtual void fun1();
virtual void fun();
virtual void fun1();
// CA,CB类的实现
void main()
CA // 不允许,因为类CA中有纯虚函数
CB // 可以,因为类CB中没有纯虚函数
---------------------------------------------------------------
虚函数在多态中间的使用:
多态一般就是通过指向基类的指针来实现的。
mydogwangwang.born();
一定是返回“dog”
myhorsepipi.born();
一定是返回“horse”
也是多态呀?
/////////////////////////////////////////////////
有一点你必须明白,就是用父类的指针在运行时刻来调用子类:
例如,有个函数是这样的:
void animal::fun1(animal *maybedog_maybehorse)
maybedog_maybehorse-&born();
参数maybedog_maybehorse在编译时刻并不知道传进来的是dog类还是horse类,所以就把它设定为animal类,具体到运行时决定了才决定用那个函数。
也就是说用父类指针通过虚函数来决定运行时刻到底是谁而指向谁的函数。
////////////////////////////////////////////////////////////////////
//用虚函数
#include &iostream.h&
class animal
~animal();
void fun1(animal *maybedog_maybehorse);
virtual void born();
void animal::fun1(animal *maybedog_maybehorse)
maybedog_maybehorse-&born();
animal::animal()
animal::~animal()
void animal::born()
cout&& &animal&;
class dog: public animal
virtual void born();
dog::dog()
dog::~dog()
void dog::born(){
cout&&&dog&;
class horse:public animal
virtual void born();
horse::horse()
horse::~horse()
void horse::born(){
cout&&&horse&;
void main()
a.fun1(&c);
//output: horse
/////////////////////////////////////////////////////////////////
//不用虚函数
#include &iostream.h&
class animal
~animal();
void fun1(animal *maybedog_maybehorse);
void born();
void animal::fun1(animal *maybedog_maybehorse)
maybedog_maybehorse-&born();
animal::animal()
animal::~animal()
void animal::born()
cout&& &animal&;
class dog: public animal
void born();
dog::dog()
dog::~dog()
void dog::born(){
cout&&&dog&;
class horse:public animal
void born();
horse::horse()
horse::~horse()
void horse::born(){
cout&&&horse&;
void main()
a.fun1(&c);
output: animal
[ 本帖最后由 lateraware 于
22:53 编辑 ]
搜索更多相关主题的帖子:
收到的鲜花
附言:我很赞同
等 级:贵宾
威 望:14
帖 子:852
专家分:1317
谢谢分享。。。
学习到了。。。
用心做一件事情就这么简单
等 级:青峰侠
帖 子:1160
专家分:1797
这种复制黏贴的帖子有意思吗?
你以为你真的就理解多态了? 我随便问你一个问题你还是回答不上来。
等 级:贵宾
威 望:14
帖 子:852
专家分:1317
回复 3楼 Devil_W
起码别人可以学到东西,你每天到这里说别人的帖子。
你又给别人带来什么了。
反正我是没有看到过。。
别人复制,也要用CTRV+C
给别人带来一点帮助我都觉得很好。。。
用心做一件事情就这么简单
等 级:贵宾
威 望:13
帖 子:302
专家分:972
以下是引用Devil_W在 10:32:48的发言:
这种复制黏贴的帖子有意思吗?
你以为你真的就理解多态了? 我随便问你一个问题你还是回答不上来。还请兄弟问问,让大家也能有进一步的认识。真心的,多交流讨论才能学到更多东西
我的群: C/C++/Assembly 喜欢交流的朋友进,进群请写消息
等 级:新手上路
帖 子:36
回复 2楼 小鱼儿c
共同学习相互进步 呵呵!
等 级:新手上路
帖 子:36
回复 3楼 Devil_W
鄙人确实是初学者,以后还望仁兄请多多指教 呵呵!
来 自:四川
等 级:贵宾
威 望:37
帖 子:2011
专家分:5959
我觉得这篇贴应该发在C++版里。
My life is brilliant
等 级:新手上路
帖 子:36
回复 7楼 lateraware
没错 呵呵 我忘了 下次记得了
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
回复 3楼 Devil_W
嗯。我也同意只是复制资料意义不大。但如果配合了你的问题,那就不同了,这将成为一个不错的讨论贴。
重剑无锋,大巧不工
版权所有,并保留所有权利。
Powered by , Processed in 0.037022 second(s), 8 queries.
Copyright&, BCCN.NET, All Rights Reserved 上传我的文档
 上传文档
 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
语言期末复习题
下载积分:2888
内容提示:C
语言期末复习题
文档格式:DOC|
浏览次数:2|
上传日期: 02:16:00|
文档星级:
全文阅读已结束,如果下载本文需要使用
 2888 积分
下载此文档
该用户还上传了这些文档
语言期末复习题
关注微信公众号温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
虚函数是为了实现多态性:允许使用统一的接口去访问不同子类的函数。[cpp]&一, 什么是虚函数  (如果不知道虚函数为何物,但又急切的想知道,那你就应该从这里开始)  简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。下面来看一段简单的代码  class A{  public:  void print(){ cout&&”This is A”&&}  };  class B:public A{  public:  void print(){ cout&&”This is B”&&}  };  int main(){ //为了在以后便于区分,我这段main()代码叫做main1  A  B  a.print();  b.print();  }  通过class A和class B的print()这个接口,可以看出这两个class因个体的差异而采用了不同的策略,输出的结果也是我们预料中的,分别是This is A和This is B。但这是否真正做到了多态性呢?No,多态还有个关键之处就是一切用指向基类的指针或引用来操作对象。那现在就把main()处的代码改一改。  int main(){ //main2  A  B  A* p1=&a;  A* p2=&b;  p1-&print();  p2-&print();  }  运行一下看看结果,哟呵,蓦然回首,结果却是两个This is A。问题来了,p2明明指向的是class B的对象但却是调用的class A的print()函数,这不是我们所期望的结果,那么解决这个问题就需要用到虚函数。class A{  public:  virtual void print(){ cout&&”This is A”&&} //现在成了虚函数了  };  class B:public A{  public:  void print(){ cout&&”This is B”&&} //这里需要在前面加上关键字virtual吗?  };  毫无疑问,class A的成员函数print()已经成了虚函数,那么class B的print()成了虚函数了吗?回答是Yes,我们只需在把基类的成员函数设为virtual,其派生类的相应的函数也会自动变为虚函数。所以,class B的print()也成了虚函数。那么对于在派生类的相应函数前是否需要用virtual关键字修饰,那就是你自己的问题了。  现在重新运行main2的代码,这样输出的结果就是This is A和This is B了。  现在来消化一下,我作个简单的总结,指向基类的指针在操作它的多态类对象时,会根据不同的类对象,调用其相应的函数,这个函数就是虚函数。纯虚函数&&&纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”。 如果一个类包含了纯虚函数,称此类为抽象类,无法创造实例。&&&&&&&&&&&&&&virtual&void funtion1()=0&虚继承虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。请看下图:  A  /  B  A  /  C  B C   /  D  类D继承自类B、C,而类B、C都继承自类A,因此出现如下图所示的局面:  A A   /  B C   /  D  在类D中会出现A。为了节省内存空间,可以将B、C对A的继承定义为虚拟继承,而A就成了虚拟基类。最后形成如下图所示的情况。  A  /  B C   /  D  代码如下:  class A;  class B:public virtual A;  class C:public virtual A;  class D:public B,public C;&&&虚函数继承与虚继承区别&&&&&虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。是C++中多态性的一个重要体现,利用基类指针访问派生类中的成员函数,这种情况下使用虚函数,这种情况下采用的是动态绑定技术。虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public,在基类的类定义中定义虚函数的一般形式:&&&virtual 函数返回值类型 虚函数名(形参表) { 函数体&}虚函数继承就是覆盖。即基类中的虚函数被派生类中的同名函数所覆盖。 是实现多态的方法。&&&&&&&&&&C++使用虚拟继承(Virtual Inheritance),使得派生类如果继承基类多次,但只有一份基类的拷贝在派生类对象中。  虚拟继承的语法:  class 派生类: virtual 基类1,virtual 基类2,...,virtual 基类n{  ...//派生类成员声明  };虚函数是为了实现多态性:允许使用统一的接口去访问不同子类的函数。[cpp]&虚继承是为了解决多重继承而出现的,能够解决菱形继承中二义性和节省内存开销参考:http://blog.csdn.net/lollipop_jin/article/details/8460931
阅读(465)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'C/C++经典面试题—虚函数、纯虚函数和虚拟继承',
blogAbstract:'虚函数',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:3,
publishTime:0,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}}

我要回帖

更多关于 构造函数可以声明为纯虚函数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信