纯虚函数的使用汇总

 

一、抽象类

含有纯虚函数的类被称为抽象类。抽象类是一种特殊的类,它是为了抽象和设计的目的而建立的,它处于继承结构的上层。抽象类是不能定义对象的,在实际中为了强调一个类是抽象类,可将该类的构造函数说明为受保护的访问控制权限。

抽象类的主要作用就是描述一组相关子类的通用操作接口。一般而言,抽象类只描述这组子类共同的操作接口,而实现交给子类来完成。

抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类没有重新定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它就可以创建该类的实例了。

举个例子来说,比如我们设计了一个交通工具的抽象类。显而易见的,由交通工具类可以派生出汽车类,飞机类等具备具体特性的类。但是对于基类交通工具来说,它的特性却是模糊的,广泛的,此时建立一个交通工具类的对象是没有任何实际意义的,对于这种没有必要建立对象的类进行约束,c++引入了抽象类的特性,而抽象类的约束控制来自于纯虚函数。

示例代码:

class Vehicle

{

public:

Vehicle(float speed,int total)

{

Vehicle::speed = speed;

Vehicle::total = total;

}

virtual void ShowMember()=0;//纯虚函数的定义

protected:

float speed;

int total;

};

class Car:public Vehicle

{

public:

Car(int aird,float speed,int total):Vehicle(speed,total)

{

Car::aird = aird;

}

virtual void ShowMember()//派生类成员函数重载

{

cout<<speed<<"|"<<total<<"|"<<aird<<endl;

}

protected:

int aird;

};

int main()

{

//Vehicle a(100,4);//错误,抽象类不能创建对象

Car b(250,150,4);

b.ShowMember();

system("pause");

}

二、纯虚函数

1、定义

纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”

virtual void funtion()=0;

虚函数的定义是:virtual void funtion();

2、引入原因

1、为了方便使用多态特性,我们常常需要在基类中定义虚函数。

2、但在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。

为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数,则编译器要求在派生类中必须予以重载以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。

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

4、在子类中一定要实现纯虚函数的定义,不然编译时会出错。

程序举例:

基类:

class A

{

public:

A();

void f1();

virtual void f2();

virtual void f3()=0;

virtual ~A();

};

子类:

class B : public A

{

public:

B();

void f1();

void f2();

void f3();

virtual ~B();

};

void main()

{

A *m_j=new B();

m_j->f1();

m_j->f2();

m_j->f3();

delete m_j;

}

f1()是一个普通的重载. 调用m_j->f1();会去调用A类中的f1(),它是在我们写好代码的时候就会定好的. 也就是根据它是由A类定义的,这样就调用这个类的函数.

f2()是虚函数. 调用m_j->f2();会调用m_j中到底保存的对象中,对应的这个函数.这是由于new的B对象.

f3()与f2()一样,只是在基类中不需要写函数现实

 

1. 虚函数和纯虚函数可以定义在同一个类(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)是不能被直接调用的。必须被子类继承重载以后,根据要求调用其子类的方法。

       以下为一个简单的虚函数和纯虚寒数的使用演示,目的是抛砖引玉!

#include <>
//father class
class Virtualbase
{
public:
        virtual void Demon()= 0; //prue virtual function
        virtual void Base() {cout<<"this is farther class"<<endl};
}

//sub class
class SubVirtual :public Virtualbase
{
public:
    void Demon() { cout<<" this is SubVirtual!"<<endl};
    void Base() { cout<<"this is subclass Base"<};
}
/* instance class and sample */
int main()
{
        Virtualbase* inst = new SubVirtual(); //multstate pointer
        inst->Demon();
        inst->Base();
}

虚函数和纯虚函数区别
观点一:
类里声明为虚函数的话,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数在它的子类里面可以被重载,这样的话,这样编译器就可以使用后期绑定来达到多态了
纯虚函数只是一个接口,是个函数的声明而已,它要留到子类里去实现。
class A{
protected:
    void foo();//普通类函数
    virtual void foo1();//虚函数
    virtual void foo2() = 0;//纯虚函数
}

观点二:
虚函数在子类里面也可以不重载的;但纯虚必须在子类去实现,这就像Java的接口一样。通常我们把很多函数加上virtual,是一个好的习惯,虽然牺牲了一些性能,但是增加了面向对象的多态性,因为你很难预料到父类里面的这个函数不在子类里面不去修改它的实现

观点三:
虚函数的类用于“实作继承”,继承接口的同时也继承了父类的实现。当然我们也可以完成自己的实现。纯虚函数的类用于“介面继承”,主要用于通信协议方面。关注的是接口的统一性,实现由子类完成。一般来说,介面类中只有纯虚函数的。
观点四:
带纯虚函数的类叫虚基类,这种基类不能直接生成对象,(否则会出现错误!)而只有被继承,并重写其虚函数后,才能使用。这样的类也叫抽象类。虚函数是为了继承接口和默认行为
纯虚函数只是继承接口,行为必须重新定义。           

PtAC++答案分数 1 作者 c++课程组 单位 广东外语外贸大学 可以将结构体变量作为一个整体进行输入或输出。 T F 分数 1 作者 c++课程组 单位 广东外语外贸大学 通过命名空间可以区分具有相同名字的函数 T F 分数 5 作者 何振峰 单位 福州大学 使用提取符(<<)可以输出各种基本数据类型的变量的值,也可以输出指针值。 T F 分数 1 作者 张德慧 单位 西安邮电大学 可以通过下标随机访问向量vector中的元素。 T F 分数 1 作者 刘莹 单位 威海职业学院 vector容器可以使用push_front()和pop_front()函数对元素进行插入、删除。 T F 分数 1 作者 何振峰 单位 福州大学 函数的参数个数和类型都相同,只是返回值不同,这不是重载函数。 T F 分数 1 作者 何振峰 单位 福州大学 重载函数可以带有默认值参数,但是要注意二义性。 T F 分数 1 作者 张德慧 单位 西安邮电大学 在C++语言中引入内联函数(inline function)的主要目的是降低空间复杂度,即缩短目标代码长度。 T F 分数 1 作者 c++课程组 单位 广东外语外贸大学 形参 int fun(int a=1,int b,int c=2)合法 T F 分数 1 作者 c++课程组 单位 广东外语外贸大学 判断数组声明及初始化语句 char str[]={'H','e','l','l','o'};是否正确。 T F 分数 1 作者 李志明 单位 燕山大学 int Sum (int a,int b=5,int c); 这个函数原型的声明没有什么不合适的地方。 T F 分数 1 作者 李志明 单位 燕山大学 两个以上的函数,具有相同的函数名,且形参的个数或形参的类型不同,或返回的数据类型不同,则称之为函数的重载。 T F 分数 1 作者 沙金 单位 石家庄铁道大学 已知class A中有数据成员int a,如果定义了A的两个对象a1,a2,它们各自的数据成员a的值可以不同. T F 分数 1 作者 张德慧 单位 西安邮电大学 C++程序中,类的构造函数名与类名相同。 T F 分数 1 作者 张德慧 单位 西安邮电大学 C++程序中,一个类的析构函数可以被重载。 T F 分数 1 作者 张德慧 单位 西安邮电大学 析构函数的作用主要是释放对象占用的资源。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 this 指针是一个系统预定义的特殊指针,指向当前正在操作的对象。 T F 分数 1 作者 杨雪华 单位 沈阳师范大学 point (*p)[3];point是类名,p为对象指针数组。 T F 分数 1 作者 杨雪华 单位 沈阳师范大学 point *p[3];point是类名,p为定义指向对象数组的指针 。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 静态成员用以解决同一个类的不同对象之间成员,包括数据成员和函数成员的共享问题。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 静态数据成员不能在类中初始化,使用时需要在类体外声明。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 常成员在函数内部可以改变其值,也可以被非常成员函数使用。 T F 分数 1 作者 杨雪华 单位 沈阳师范大学 常数据成员的值必须初始化,且不能改变。 T F 分数 1 作者 杨雪华 单位 沈阳师范大学 常成员函数既可以被常对象调用,也可以被非常对象调用。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 友元函数不是类的成员函数,只是独立于该类的一般函数。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 一个类的友元函数可以访问该类的私有成员。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 友元类之间的关系不能传递,但能继承。 T F 分数 1 作者 何振峰 单位 福州大学 对每个可重载的运算符来讲,它既可以重载为友元函数,又可以重载为成员函数,还可以重载为非成员函数。 T F 分数 1 作者 何振峰 单位 福州大学 多数运算符可以重载,个别运算符不能重载,运算符重载是通过函数定义实现的。 T F 分数 1 作者 何振峰 单位 福州大学 对单目运算符重载为友元函数时,可以说明一个形参。而重载为成员函数时,不能显式说明形参。 T F 分数 1 作者 何振峰 单位 福州大学 重载运算符可以保持原运算符的优先级和结合性不变。 T F 分数 1 作者 何振峰 单位 福州大学 预定义的提取符和插入符是可以重载的。 T F 分数 1 作者 董俊 单位 燕山大学 对于++运算符的重载,要求重载两种形式,一种是前置++,一种是后置++。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 赋值运算符“ =”只能重载为成员函数。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 重载运算符()、[]、->或者=赋值运算符,运算符重载函数必须声明为类的成员函数。 T F 分数 1 作者 黄万丽 单位 曲阜师范大学 在多继承中,派生类的构造函数需要依次调用其基类的构造函数,调用顺序取决于定义派生类时所指定的各基类的顺序。 T F 分数 1 作者 黄万丽 单位 曲阜师范大学 多重继承派生类的构造函数,需要调用所有的基类构造函数来完成各基类数据成员的初始化。 T F 分数 1 作者 李志明 单位 燕山大学 派生类D由基类A公有派生。假设基类A中有一个公有函数成员add(原型:int add (int x, int y););在派生类D中,派生一个公有函数成员add(原型:int add (int x, int y, int z););则在语句(D d;d.add(10,20);)中,不可以正常调用add函数。 T F 分数 1 作者 董俊 单位 燕山大学 基类中的私有成员不论通过何种派生方式,到了派生类中均变成不可直接访问成员。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 如果公有派生,则可以用派生类对象给基类对象赋值。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 如果公有派生,则可以用基类对象初始化派生类的引用。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 如果公有派生,则可以用基类对象的地址赋值给派生类的指针。 T F 分数 1 作者 李志明 单位 燕山大学 类的组合关系可以用“Has-A”描述;类间的继承与派生关系可以用“Is-A”描述。 T F 分数 1 作者 黄万丽 单位 曲阜师范大学 基类与派生类对象之间具有赋值兼容的关系,可以进行类型间的转换,派生类对象可以直接转换为基类对象,同样基类对象也可以直接转换为派生类对象 。 T F 分数 1 作者 黄万丽 单位 曲阜师范大学 如果函数的参数是基类对象或基类对象的引用,函数调用时的实参可以是派生类对象。 T F 分数 1 作者 何振峰 单位 福州大学 虚函数是用virtual 关键字说明的成员函数。 T F 分数 1 作者 何振峰 单位 福州大学 因为静态成员函数不能是虚函数,所以它们不能实现多态。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 通过基类指针调用基类和派生类中的同名虚函数时,若该指针指向一个派生类的对象,那么被调用的是基类的虚函数。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 通过基类引用调用基类和派生类中的同名虚函数时,若该引用引用的是一个派生类的对象,那么被调用的是派生类的虚函数。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 通过基类的指针删除派生对象时,通常情况下只调用基类的析构函数。但是,删除一个派生类的对象时应该先调派生类析构函数,然后调用基类的析构函数。解决办法:把基类的析构函数声明为虚析构函数。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 类的构造函数可以定义为虚函数。 T F 分数 1 作者 何振峰 单位 福州大学 抽象类是指一些没有说明对象的类。 T F 分数 1 作者 黄淑伟 单位 沈阳师范大学 包含纯虚函数的类叫抽象类。 T F 分数 1 作者 高巍然 单位 西安邮电大学 构造函数可以声明为纯虚函数。 T F 分数 1 作者 高巍然 单位 西安邮电大学 如果派生类的成员函数的原型与基类中被定义为虚函数的成员函数原型相同,那么,这个函数自动继承基类中虚函数的特性。 T F 分数 1 作者 高巍然 单位 西安邮电大学 重定义虚函数的派生类必须是公有继承的。 T F 分数 1 作者 高巍然 单位 西安邮电大学 对于从基类继承的虚函数,派生类也可以不进行重定义。 T F 分数 1 作者 高巍然 单位 西安邮电大学 纯虚函数与函数体为空的虚函数等价。 T F 分数 1 作者 张德慧 单位 西安邮电大学 当向量对象的内存用完之后,就会产生越界错误。 T F 分数 1 作者 黄万丽 单位 曲阜师范大学 vector容器和list容器都是序列式容器,都有排序的sort()成员函数。 T F 分数 1 作者 黄万丽 单位 曲阜师范大学 向STL中的关联型容器set中插入元素时,使用set的方法insert(pos, elem),是指在pos位置插入元素elem,元素elem一定在pos指定的位置。 T F 分数 1 作者 黄万丽 单位 曲阜师范大学 双向链表list的方法merge()可以将两个list容器合并,在使用merge()方法之前如果两个list容器中的数据是有序的(如从小到大排列),那么两个容器合并后,容器中的元素仍然是有序的(如从小到大排列)。 T F 分数 1 作者 刘莹 单位 威海职业学院 set/multiset的区别是set用来存储一组无重复的元素,而multiset允许存储有重复的元素。 T F 分数 1 作者 刘莹 单位 威海职业学院 STL中关联型容器都是有序的。 T F 分数 1 作者 刘莹 单位 威海职业学院 映射容器里存储的元素都是成对存在的。 T F 分数 1 作者 张德慧 单位 西安邮电大学 迭代器是对象,它的作用类似于指向元素的指针。 T F 分数 1 作者 张德慧 单位 西安邮电大学 STL算法使用迭代器间接地对容器中的元素进行操作。 T F 分数 1 作者 何振峰 单位 福州大学 记录流的当前格式化状态标志字中的每一位用于记录一种格式,这种格式是不能被设置或清除的。 T F 分数 1 作者 何振峰 单位 福州大学 设置和清除格式标志字的成员函数需要通过对象来引用它们,输出显示格式的对象通常是cout。 T F 分数 1 作者 何振峰 单位 福州大学 操纵符本身是一个对象,它可以直接被提取符或插入符操作。 T F 分数 1 作者 何振峰 单位 福州大学 get()函数不能从流中提取终止字符,终止字符仍留在流中。getline()函数可以从流中提取终止字符,但终止字符被丢弃。( T F 分数 1 作者 何振峰 单位 福州大学 使用打开文件函数open()之前,需要定义一个流类对象,使用open()函数来操作该对象。(。 T F 分数 1 作者 何振峰 单位 福州大学 使用关闭文件函数close()关闭一个文件时,流对象仍存在。 T F 分数 1 作者 何振峰 单位 福州大学 打开ASCⅡ码流文件和二进制流文件时,打开方式是相同的。 T F 分数 1 作者 何振峰 单位 福州大学 read()和write()函数可以读写文本文件,也可以读写二进制文件。 T F 分数 1 作者 何振峰 单位 福州大学 流的状态包含流的内容、长度和下一次提取或插入操作的当前位置。 T F 分数 1 作者 何振峰 单位 福州大学 seekg()函数和seekp()函数分别用来定位读指针和写指针的。如果使用seek()函数可以同时定义读写指针。 T F 分数 1 作者 张德慧 单位 西安邮电大学 文件流对象的成员函数read()和write()函数可以读写文本文件,也可以读写二进制文件。 。 T F 分数 1 作者 何振峰 单位 福州大学 预定义的插入符从键盘上接收数据是不带缓冲区的。 T F 分数 1 作者 黄万丽 单位 曲阜师范大学 有如下语句序列 第1行: int a=1; 第2行: try{ 第3行: if(a==1) throw(a); 第4行: a++; 第5行: } 第6行: catch(int b){ 第7行: cout << “error! a = ” << b << endl; 第8行: } 以上语句的第6行有编译错误,只能写成catch(int)。 T F 分数 1 作者 黄万丽 单位 曲阜师范大学 异常处理的catch{ }语句块必须紧跟try{ }语句块之后,这两个语句之间不能插入另外语句。 T F
06-30
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值