文档库 最新最全的文档下载
当前位置:文档库 › 抽象类与纯虚函数

抽象类与纯虚函数

抽象类与纯虚函数
抽象类与纯虚函数

纯虚函数和抽象类:

含有纯虚函数的类是抽象类,不能生成对象,只能派生。他派生的类的纯虚函数没有被改写,那么,它的派生类还是个抽象类。

定义纯虚函数就是为了让基类不可实例化化,因为实例化这样的抽象数据结构本身并没有意义.或者给出实现也没有意义

一. 纯虚函数

在许多情况下,在基类中不能给出有意义的虚函数定义,这时可以把它说明成纯虚函数,把它的定义留给派生类来做。定义纯虚函数的一般形式为:

class 类名{

virtual 返回值类型函数名(参数表)= 0; // 后面的"= 0"是必须的,否则,就成虚函数了

};

纯虚函数是一个在基类中说明的虚函数,它在基类中没有定义,要求任何派生类都定义自己的版本。纯虚函数为各派生类提供一个公共界面。

从基类继承来的纯虚函数,在派生类中仍是虚函数。

二. 抽象类

1. 如果一个类中至少有一个纯虚函数,那么这个类被称为抽象类(abstract class)。

抽象类中不仅包括纯虚函数,也可包括虚函数。抽象类中的纯虚函数可能是在抽象类中定义的,也可能是从它的抽象基类中继承下来且重定义的。

2. 抽象类特点,即抽象类必须用作派生其他类的基类,而不能用于直接创建对象实例。

一个抽象类不可以用来创建对象,只能用来为派生类提供一个接口规范,派生类中必须重载基类中的纯虚函数,否则它仍将被看作一个抽象类。

3. 在effective c++上中提到,纯虚函数可以被实现(定义),但是,不能创建对象实例,这也体现了抽象类的概念。

三. 虚析构函数

虚析构函数: 在析构函数前面加上关键字virtual进行说明,称该析构函数为虚析构函数。虽然构造函数不能被声明为虚函数,但析构函数可以被声明为虚函数。

一般来说,如果一个类中定义了虚函数,析构函数也应该定义为虚析构函数。

例如:

class B

{

virtual ~B(); //虚析构函数

};

关于更多的精彩解释,请参考<< c++编程思想 >> 一书。

*/

#include

class Animal

{

public:

virtual void shout() = 0;

virtual void impl() = 0;

virtual ~Animal() {printf(" Animal destory! \n");}; // 虚析构函数};

void Animal::impl() // 纯虚函数也可以被实现。

{

printf(" Animal: I can be implement! \n");

}

class Dog: public Animal

{

public:

virtual void shout() // 必须要被实现,即使函数体是空的

{

printf(" wang! wang! wang! \n");

}

virtual void impl()

{

printf(" implement of Dog! \n");

}

virtual ~Dog() {printf(" Dog destory! \n");}; // 虚析构函数

};

class Cat: public Animal

{

public:

virtual void shout() // 必须要被实现,即使函数体是空的

{

printf(" miao! miao! miao! \n");

}

virtual void impl()

{

printf(" implement of Cat! \n");

}

virtual ~Cat() {printf(" Cat destory! \n");}; // 虚析构函数};

/*

Animal f() // error, 抽象类不能作为返回类型

{

}

void display( Animal a) //error, 抽象类不能作为参数类型

{

}

*/

//ok,可以声明抽象类的引用

Animal &display(Animal &a)

{

Dog d;

Animal &p = d;

return p;

}

void test_func()

{

//Animal a; // error: 抽象类不能建立对象

Dog dog; //ok,可以声明抽象类的指针

Cat cat; //ok,可以声明抽象类的指针

Animal *animal = &dog;

animal->shout();

animal->impl();

printf("\n");

animal = &cat;

animal->shout();

animal->impl();

printf("\n");

}

int main()

{

test_func();

while(1);

}

/* result:

wang! wang! wang! implement of Dog!

miao! miao! miao!

implement of Cat!

Cat destory!

Animal destory!

Dog destory!

Animal destory!

*/

C++虚函数与纯虚函数用法与区别

C++虚函数与纯虚函数用法与区别 1.C++虚函数与纯虚函数用法与区别,.虚函数和纯虚函数可以定义在同一个类(class)中,含有纯虚函数的类被称为抽象类(abstract class),而只含有虚函数的类(class)不能被称为抽象类(abstract class)。 2.虚函数可以被直接使用,也可以被子类(sub class)重载以后以多态的形式调用,而纯虚函数必须在子类(sub class)中实现该函数才可以使用,因为纯虚函数在基类(base class) 只有声明而没有定义。 3.虚函数和纯虚函数都可以在子类(sub class)中被重载,以多态的形式被调用。 4.虚函数和纯虚函数通常存在于抽象基类(abstract base class -ABC)之中,被继承的子类重载,目的是提供一个统一的接口。 5.虚函数的定义形式:virtual {method body} 纯虚函数的定义形式:virtual { } = 0; 在虚函数和纯虚函数的定义中不能有static标识符,原因很简单,被static修饰的函数在编译时候要求前期bind,然而虚函数却是动态绑定(run-time bind),而且被两者修饰的函数生命周期(life recycle)也不一样。 6. 如果一个类中含有纯虚函数,那么任何试图对该类进行实例化的语句都将导致错误的产生,因为抽象基类(ABC)是不能被直接调用的。必须被子类继承重载以后,根据要求调用其子类的方法。 //father class class Virtualbase { public: virtual void Demon()= 0; //prue virtual function virtual void Base() {cout<<"this is farther class"<}; }

虚函数和纯虚函数

虚函数和纯虚函数 在面向对象的C++语言中,虚函数(virtual function)是一个非常重要的概念。因为它充分体现了面向对象思想中的继承和多态性这两大特性,在C++语言里应用极广。比如在微软的MFC类库中,你会发现很多函数都有virtual关键字,也就是说,它们都是虚函数。难怪有人甚至称虚函数是C++语言的精髓。 那么,什么是虚函数呢,我们先来看看微软的解释: 虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。 ——摘自MSDN 这个定义说得不是很明白。MSDN中还给出了一个例子,但是它的例子也并不能很好的说明问题。我们自己编写这样一个例子: #include "stdio.h" #include "conio.h" class Parent { public: char data[20]; void Function1(); virtual void Function2(); // 这里声明Function2是虚函数 }parent; 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(); } child; void Child::Function1() { printf("This is child,function1\n");

纯虚函数

#include using namespace std; const double PI=3.1415926; class Shape { public: virtual double Area()=0; }; class Triangle:public Shape { private: double d,h; public: Triangle(double di,double gao) { d=di; h=gao; } double Area() { cout<<"三角形面积为:"; return d*h*1/2; } }; class Circle:public Shape { private: double r; public: Circle(double radius) { r=radius; } double Area() { cout<<"圆面积为:"; return PI*r*r; } }; class Ractangle:public Shape

{ private: double a,b; public: Ractangle(double chang,double kuang) { a=chang; b=kuang; } double Area() { cout<<"矩形面积为:"; return a*b; } }; void main() { Shape *p; double a,b; cout<<"请输入三角形底边和高:"; cin>>a>>b; Triangle t(a,b); p=&t; cout<Area()<>a; Circle c(a); p=&c; cout<Area()<>a>>b; Ractangle r(a,b); p=&r; cout<Area()<

c++抽象类和纯虚函数

纯虚函数和抽象类: 含有纯虚函数的类是抽象类,不能生成对象,只能派生。他派生的类的纯虚函数没有被改写,那么,它的派生类还是个抽象类。 定义纯虚函数就是为了让基类不可实例化化,因为实例化这样的抽象数据结构本身并没有意义.或者给出实现也没有意义 一. 纯虚函数 在许多情况下,在基类中不能给出有意义的虚函数定义,这时可以把它说明成纯虚函数,把它的定义留给派生类来做。定义纯虚函数的一般形式为: class 类名{ virtual 返回值类型函数名(参数表)= 0; // 后面的"= 0"是必须的,否则,就成虚函数了}; 纯虚函数是一个在基类中说明的虚函数,它在基类中没有定义,要求任何派生类都定义自己的版本。纯虚函数为各派生类提供一个公共界面。 从基类继承来的纯虚函数,在派生类中仍是虚函数。 二. 抽象类 1. 如果一个类中至少有一个纯虚函数,那么这个类被称为抽象类(abstract class)。 抽象类中不仅包括纯虚函数,也可包括虚函数。抽象类中的纯虚函数可能是在抽象类中定义的,也可能是从它的抽象基类中继承下来且重定义的。 2. 抽象类特点,即抽象类必须用作派生其他类的基类,而不能用于直接创建对象实例。 一个抽象类不可以用来创建对象,只能用来为派生类提供一个接口规范,派生类中必须重载基类中的纯虚函数,否则它仍将被看作一个抽象类。 3. 在effective c++上中提到,纯虚函数可以被实现(定义),但是,不能创建对象实例,这也体现了抽象类的概念。 三. 虚析构函数 虚析构函数: 在析构函数前面加上关键字virtual进行说明,称该析构函数为虚析构函数。虽然构造函数不能被声明为虚函数,但析构函数可以被声明为虚函数。 一般来说,如果一个类中定义了虚函数,析构函数也应该定义为虚析构函数。 例如: class B { virtual ~B(); //虚析构函数 … };

虚函数和纯虚函数的作用与区别

虚函数和纯虚函数的作用与区别 虚函数为了重载和多态的需要,在基类中是由定义的,即便定义是空,所以子类中可以重写也可以不写基类中的函数! 纯虚函数在基类中是没有定义的,必须在子类中加以实现,很像java中的接口函数! 虚函数 引入原因:为了方便使用多态特性,我们常常需要在基类中定义虚函数。 class Cman { public: virtual void Eat(){……}; void Move(); private: }; class CChild : public CMan { public: virtual void Eat(){……}; private: }; CMan m_man; CChild m_child; //这才是使用的精髓,如果不定义基类的指针去使用,没有太大的意义 CMan *p ; p = &m_man ; p->Eat(); //始终调用CMan的Eat成员函数,不会调用CChild 的 p = &m_child; p->Eat(); //如果子类实现(覆盖)了该方法,则始终调用CChild的Eat函数 //不会调用CMan 的Eat 方法;如果子类没有实现该函数,则调用CMan的Eat函数 p->Move(); //子类中没有该成员函数,所以调用的是基类中的 纯虚函数 引入原因: 1、同“虚函数”; 2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。 //纯虚函数就是基类只定义了函数体,没有实现过程定义方法如下 // virtual void Eat() = 0; 直接=0 不要在cpp中定义就可以了 //纯虚函数相当于接口,不能直接实例话,需要派生类来实现函数定义 //有的人可能在想,定义这些有什么用啊,我觉得很有用 //比如你想描述一些事物的属性给别人,而自己不想去实现,就可以定 //义为纯虚函数。说的再透彻一些。比如盖楼房,你是老板,你给建筑公司 //描述清楚你的楼房的特性,多少层,楼顶要有个花园什么的 //建筑公司就可以按照你的方法去实现了,如果你不说清楚这些,可能建筑

c++多态性与虚函数习题答案

多态性与虚函数 1.概念填空题 1.1 C++支持两种多态性,分别是编译时和运行时。 1.2在编译时就确定的函数调用称为静态联编,它通过使用函数重载,模板等实现。 1.3在运行时才确定的函数调用称为动态联编,它通过虚函数来实现。 1.4虚函数的声明方法是在函数原型前加上关键字virtual。在基类中含有虚函数,在派生类中的函数没有显式写出virtual关键字,系统依据以下规则判断派生类的这个函数是否是虚函数:该函数是否和基类的虚函数同名;是否与基类的虚函数参数个数相同、类型;是否与基类的虚函数相同返回类型。如果满足上述3个条件,派生类的函数就是虚函数。并且该函数覆盖基类的虚函数。 1.5 纯虚函数是一种特别的虚函数,它没有函数的函数体部分,也没有为函数的功能提供实现的代码,它的实现版本必须由派生类给出,因此纯虚函数不能是友元函数。拥有纯虚函数的类就是抽象类类,这种类不能实例化。如果纯虚函数没有被重载,则派生类将继承此纯虚函数,即该派生类也是抽象。 3.选择题 3.1在C++中,要实现动态联编,必须使用(D)调用虚函数。 A.类名 B.派生类指针 C.对象名 D.基类指针 3.2下列函数中,不能说明为虚函数的是(C)。 A.私有成员函数 B.公有成员函数 C.构造函数 D.析构函数 3.3在派生类中,重载一个虚函数时,要求函数名、参数的个数、参数的类型、参数的顺序和函数的返回值(A)。 A.相同 B.不同 C.相容 D.部分相同 3.4当一个类的某个函数被说明为virtual时,该函数在该类的所有派生类中(A)。 A.都是虚函数 B.只有被重新说明时才是虚函数 C.只有被重新说明为virtual时才是虚函数 D.都不是虚函数 3.5(C)是一个在基类中说明的虚函数,它在该基类中没有定义,但要求任何派生类都必须定义自己的版本。 A.虚析构函数B.虚构造函数 C.纯虚函数D.静态成员函数 3.6 以下基类中的成员函数,哪个表示纯虚函数(C)。 A.virtual void vf(int);B.void vf(int)=0; C.virtual void vf( )=0;D.virtual void vf(int){ } 3.7下列描述中,(D)是抽象类的特性。 A.可以说明虚函数 B.可以进行构造函数重载 C.可以定义友元函数 D.不能定义其对象 3.8类B是类A的公有派生类,类A和类B中都定义了虚函数func( ),p是一个指向类A对象的指针,则p->A::func( )将(A)。

虚函数的作用

条款14: 确定基类有虚析构函数 有时,一个类想跟踪它有多少个对象存在。一个简单的方法是创建一个静态类成员来统计对象的个数。这个成员被初始化为0,在构造函数里加1,析构函数里减1。(条款m26里说明了如何把这种方法封装起来以便很容易地添加到任何类中,“my article on counting objects”提供了对这个技术的另外一些改进) 设想在一个军事应用程序里,有一个表示敌人目标的类: class enemytarget { public: enemytarget() { ++numtargets; } enemytarget(const enemytarget&) { ++numtargets; } ~enemytarget() { --numtargets; } static size_t numberoftargets() { return numtargets; } virtual bool destroy(); // 摧毁enemytarget对象后 // 返回成功 private: static size_t numtargets; // 对象计数器 }; // 类的静态成员要在类外定义; // 缺省初始化为0 size_t enemytarget::numtargets; 这个类不会为你赢得一份政府防御合同,它离国防部的要求相差太远了,但它足以满足我们这儿说明问题的需要。 敌人的坦克是一种特殊的敌人目标,所以会很自然地想到将它抽象为一个以公有继承方式从enemytarget派生出来的类(参见条款35及m33)。因为不但要关心敌人目标的总数,也要关心敌人坦克的总数,所以和基类一样,在派生类里也采用了上面提到的同样的技巧: class enemytank: public enemytarget { public: enemytank() { ++numtanks; } enemytank(const enemytank& rhs) : enemytarget(rhs) { ++numtanks; }

虚函数纯虚函数普通函数.docx

C++在继承中虚函数、纯虚函数、普通函数,三者的区别 1.虚函数(impure virtual) C++的帰函数主要作用是“运行时多态〃,父类屮提供虚函数的实现,为子类提供默认的函数实现。 子类可以重写父类的虚函数实现子类的特殊化。 如下就是一个父类中的虚函数: class A {public: virtual void out2(string s) { cout?"A(out2):"?s?endl; } 2.纯虚函数(pure virtual) C++中包含纯虚函数的类,被称为是"抽彖类〃。抽彖类不能使用newtU对彖,只有实现了这个纯虚函数的子类才能new出对象。 C++中的纯虚函数更像是〃只提供申明,没有实现〃,是对子类的约束,是“接口继承〃。 C++中的纯虚函数也是一种“运行时多态〃。 如下而的类包含纯虚函数,就是“抽彖类〃: class A {public: virtual void outl(string s)=0; virtual void out2(string s) { cout?"A(out2):"?s?endl; } }; 百 3.普通函数(no-virtual) 普通函数是静态编译的,没有运行时多态,只会根据指针或引用的“字面值〃类对象,调用自己的普通函数。 普通函数是父类为子类提供的“强制实现〃。 因此,在继承关系屮,子类不应该重写父类的普通函数,因为函数的调用至于类对彖的字面值有关。 4.程序综合实例 心 #inelude using namespace std; class A {public: virtual void outl()=0; ///由子类实现virtual ~A(){};

抽象基类和纯虚函数

抽象基类和纯虚函数 抽象类和具体类 包含纯虚函数的类不能实例化对象,是抽象类 如果抽象类的派生类实现了所有积累中的纯虚函数,则不再是抽象类 抽象类存在的意义是作为其他类的基类,也较抽象基类 构造函数的执行顺序:从上至下 析构函数的执行顺序:从下至上 创建对象时要执行正确的构造函数 撤销对象时要执行正确的析构函数 问题:动态对象的创建和撤销 虚析构函数 动态对象的创建 动态创建的对象没有问题 New classname(···); 动态对象的撤销 Delete 基类指针; 如果基类指针指向的是派生类的对象呢? 析构函数可以声明为虚函数 Delete 基类指针; 程序会根据积累指针指向的对象的类型确定要调用的析构函数 如果基类的析构函数为虚函数,则所派生的类的析构函数都是虚函数 如果要操作具有继承关系的类的动态对象,最好使用虚析构函数 文件和流——支持大量数据的处理:输入,存储 对文件执行的操作只要求我们掌握对几个函数的操作就行 如果说你不懂对文件的操作和处理,你永远也无法选好编程,你的程序永远也写不好,操作系统能够把外设和文件统一管理。 文件可以保存程序的运行结果 文件使程序处理大量的数据成为可能 大型系统的运行需要文件支持 C++将文件看成有序的字节流 文件被打开后,操作系统为该文件的建立的一个缓冲区,或称为一个字节序列,即流 普通文件 二进制文件 文本文件 输入输出设备:键盘,显示器,打印机等 标准输入流(用指针stdin操作) 标准输出流(用指针stdout操作)

C++采用相同的方式操作普通文件和I/O设备 文件的操作 格式化输入输出(文本) 块输入输出(二进制) 文件操作过程 1.建立并打开文件 2.操作文件:读,写 3.关闭文件 打开文件或建立一个新文件 FILE *fopen(const char *filename,const char *mode); filename——路劲及文件名 mode——打开方式 关闭文件 Int fclose(FILE *stream); Stream——要关闭的文件 读写文件——格式化操作(文本文件) Int fscanf(File *stream,·······); Int fprintf(File *stream,·······); 读写文件——快读写方式(二进制文件) size_t fwrite(const void*buffer,size_t size,size_t count,File *stream); size_t fread(const void*buffer,size_t size,size_t count,File *stream);

虚函数与纯虚函数

接口继承与实现继承 1、继承的总是成员函数的接口。对于一个基类是正确的事情,对于它的派生类必须也是正确的。 2、声明纯虚函数的目的是使派生类仅继承函数接口,而函数的实现由派生类去完成。 3、声明虚函数的目的是使派生类既能继承函数的接口,又能继承函数的缺省实现。 4、声明实函数的目的是使派生类既能继承函数的接口,又使派生类继承函数的强制实现。 虚函数与函数重载: 虚函数可以在派生类中重新定义,实函数也可以在派生类中重新定义即重载,而两者的区别是:对于虚函数使用动态联编,只要基类指针和派生类指针都指向派生类对象,用基类指针和派生类指针访问虚函数时,都访问以派生类定义的虚函数代码。对于实函数重载使用静态联编,即使基类指针和派生类指针都指向派生类对象,用基类指针访问虚函数时,将调用基类定义的代码,而用派生类指针访问虚函数时,将调用派生类定义的代码。所以,为了提高程序的质量,很少使用实函数重载,尽管它在语法上是行得通的。 纯虚函数最显出的两个特征: 1、它们必须由继承它们的非抽象类重新说明。 2、它们在抽象类中没有定义。 因此纯虚函数的目的就是使派生类必须实现某种功能 虚函数的目的就是使派生类即继承缺省的实现,也同时继承了函数接口。 当然使用虚函数时要慎重使用它的缺省实现。 一般都是纯虚函数与虚函数配合使用,或者纯虚函数与实函数配合使用,即让派生类必须具备某种功能,又提供了可以重用的缺省代码。 虚函数是动态联编的基础,属于包含多态类型,虚函数是非静态的成员函数,虚函数经过派生之后,在类族中就可以实现过程中得多态。虚函数的定义实际就是在原有的普通函数成员前面使用virtual关键字来限定,虚函数声明只能出现在函数原型声明中,而不能在成员的函数体实现的时候。 纯虚函数是一个在基类中说明得虚函数,他在该基类中没有定义具体的操作内容,要求各派生类根据实际需要定义自己的版本。实际上,他与一般虚函数成员在书写格式上的不同就在于后面加了"=0 "。声明为纯虚函数之后,基类中就不再给出函数的实现部分。纯虚函数得函数体由派生类给出。 多态性的实现与静态联编、动态联编有关。静态联编支持的多态性称为编译时的多态性,也称静态多态性,它是通过函数重载和运算符重载实现的。动态联编支持的多态性称为运行时的多态性,也称动态多态性,它是通过继承和虚函数实现的。

C++中的虚函数(virtual function)

C++中的虚函数(virtual function) 一.简介 虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。假设我们有下面的类层次: class A { public: virtual void foo() { cout << "A::foo() is called" << endl;} }; class B: public A { public: virtual void foo() { cout << "B::foo() is called" << endl;} }; 那么,在使用的时候,我们可以: A * a = new B(); a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B 的! 这个例子是虚函数的一个典型应用,通过这个例子,也许你就对虚函数有了一些概念。它虚就虚在所谓“推迟联编”或者“动态联编”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被成为“虚”函数。 虚函数只能借助于指针或者引用来达到多态的效果,如果是下面这样的代码,则虽然是虚函数,但它不是多态的: class A { public: virtual void foo(); }; class B: public A {

virtual void foo(); }; void bar() { A a; a.foo(); // A::foo()被调用 } 1.1 多态 在了解了虚函数的意思之后,再考虑什么是多态就很容易了。仍然针对上面的类层次,但是使用的方法变的复杂了一些: void bar(A * a) { a->foo(); // 被调用的是A::foo() 还是B::foo()? } 因为foo()是个虚函数,所以在bar这个函数中,只根据这段代码,无从确定这里被调用的是A::foo()还是B::foo(),但是可以肯定的说:如果a指向的是A类的实例,则A::foo()被调用,如果a指向的是B类的实例,则B::foo()被调用。 这种同一代码可以产生不同效果的特点,被称为“多态”。 1.2 多态有什么用? 多态这么神奇,但是能用来做什么呢?这个命题我难以用一两句话概括,一般的C++教程(或者其它面向对象语言的教程)都用一个画图的例子来展示多态的用途,我就不再重复这个例子了,如果你不知道这个例子,随便找本书应该都有介绍。我试图从一个抽象的角度描述一下,回头再结合那个画图的例子,也许你就更容易理解。 在面向对象的编程中,首先会针对数据进行抽象(确定基类)和继承(确定派生类),构成类层次。这个类层次的使用者在使用它们的时候,如果仍然在需要基类的时候写针对基类的代码,在需要派生类的时候写针对派生类的代码,就等于类层次完全暴露在使用者面前。如果这个类层次有任何的改变(增加了新类),都需要使用者“知道”(针对新类写代码)。这样就增加了类层次与其使用者之间的耦合,有人把这种情况列为程序中的“bad smell”之一。 多态可以使程序员脱离这种窘境。再回头看看1.1中的例子,bar()作为A-B 这个类层次的使用者,它并不知道这个类层次中有多少个类,每个类都叫什么,但是一样可以很好的工作,当有一个C类从A类派生出来后,bar()也不需要“知

C++中重载与重写函数区别及虚函数

C++中重载与重写函数区别及虚函数 C++中的虚函数(virtual function) 1.简介 虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。假设我们有下面的类层次: class A { public: virtual void foo() { cout << "A::foo() is called" << endl;} }; class B: public A { public: virtual void foo() { cout << "B::foo() is called" << endl;} }; 那么,在使用的时候,我们可以: A * a = new B(); a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的! 这个例子是虚函数的一个典型应用,通过这个例子,也许你就对虚函数有了一些概念。它虚就虚在所谓“推迟联编”或者“动态联编”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被成为“虚”函数。

虚函数只能借助于指针或者引用来达到多态的效果,如果是下面这样的代码,则虽然是虚函数,但它不是多态的: class A { public: virtual void foo(); }; class B: public A { virtual void foo(); }; void bar() { A a; a.foo(); // A::foo()被调用 } 1.1 多态 在了解了虚函数的意思之后,再考虑什么是多态就很容易了。仍然针对上面的类层次,但是使用的方法变的复杂了一些: void bar(A * a) { a->foo(); // 被调用的是A::foo() 还是B::foo()? } 因为foo()是个虚函数,所以在bar这个函数中,只根据这段代码,无从确定这里被调用的是A::foo()还是B::foo(),但是可以肯定的说:如果a

虚函数和纯虚函数区别

虚函数和纯虚函数区别: 虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public,在基类的类定义中定义虚函数的一般形式: virtual 函数返回值类型虚函数名(形参表) { 函数体 } 相同点:虚函数和纯虚函数都是为了实现多态机制的,目的是给派生类修改基类行为的机会。 不同点:虚函数可以在基类中定义默认的行为,如果派生类没有对其行为进行覆盖,则基类的默认行为生效,如果派生类对其覆盖,则会自动调用派生类的行为;纯虚函数不在基类中提供默认的行为,只是提供一个接口声明。 因此,纯虚函数只是声明接口,不提供行为实现。包含了纯虚函数的类被称为虚基类,无法声明实例。纯虚类生来就是需要被继承并修改其行为的。 观点一: 虚函数在子类里面也可以不重载的;但纯虚必须在子类去实现,这就像Java的接口一样。通常我们把很多函数加上virtual,是一个好的习惯,虽然牺牲了一些性能,但是增加了面向对象的多态性,因为你很难预料到父类里面的这个函数不在子类里面不去修改它的实现观点二: 带纯虚函数的类叫虚基类,这种基类不能直接生成对象,而只有被继承,并重写其虚函数后,才能使用。这样的类也叫抽象类。虚函数是为了继承接口和默认行为 观点三: 类里声明为虚函数的话,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数在它的子类里面可以被重载,这样的话,这样编译器就可以使用后期绑定来达到多态了。纯虚函数只是一个接口,是个函数的声明而已,它要留到子类里去实现。 观点四: 虚函数的类用于CMS的“实作继承”,继承接口的同时也继承了父类的实现。当然我们也可以完成自己的实现。纯虚函数的类用于“介面继承”,主要用于通信协议方面。关注的是接口的统一性,实现由子类完成。一般来说,介面类中只有纯虚函数的。

虚函数-虚表-虚指针-多态性-如何实现多态-纯虚函数-抽象类(经典之作)

有虚函数的类,其对象占用的内存空间的前四个字节存放指向虚表的指针。 1.非虚拟继承时,无论派生类是否定义新的虚函数,基类和派生类总是共享一个虚函数表, 不需要另加指向虚函数的指针。 2. 虚拟继承时,若是派生类只是继承或重写基类中虚函数,则基类和派生类是共享一个虚函数表;若派生类新定义了虚函数,则需要新加一个虚指针指向新的虚函数表。 1. 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数。 2. 存在虚函数的类都有一个一维的虚函数表叫做虚表。类的对象有一个指向虚表开始的 虚指针。虚表是和类对应的,虚表指针是和对象对应的。 3. 多态性是一个接口多种实现,是面向对象的核心。分为类的多态性和函数的多态性。 4. 多态用虚函数来实现,结合动态绑定。 5. 纯虚函数是虚函数再加上= 0。 6. 抽象类是指包括至少一个纯虚函数的类。 纯虚函数:virtual void breathe()=0;即抽象类!必须在子类实现这个函数!即先有名称,没内容,在派生类实现内容! 我们先看一个例子:例1- 1 #include class animal { public: void sleep() { cout<<"animal sleep"<breathe();

相关文档