-
2019-09-21 21:41:41
抽象类的定义就是,含有纯虚函数的类。纯虚函数跟一般的虚函数有很大不同。我们下面来了解下纯虚函数。
一.纯虚函数
即使有的虚函数在基类中不需要做任何工作,我们也要写出一个空的函数体,这时这个函数体没有什么意义,重要的是此虚函数的原型声明。C++为我们提供了纯虚函数,让我们在这种情况下不用写函数实现,只给出函数原型作为整个类族的统一接口就可以了,函数的实现可以在派生类中给出。
纯虚函数是在基类中声明的,声明形式为:
virtual 函数类型 函数名(参数表) = 0;
大家可以看到,纯虚函数的声明形式与一般虚函数类似,只是最后加了个“=0”。纯虚函数这样声明以后,在基类中就不再给出它的实现了,各个派生类可以根据自己的功能需要定义其实现。
二.抽象类
上面说到,抽象类就是含有纯虚函数的类。抽象类可以为某个类族定义统一的接口,接口的具体实现是在派生类中给出。这种实现就具有多态特性。
这里要注意的是,抽象类的派生类如果没有实现所有的纯虚函数,只给出了部分纯虚函数的实现,那么这个派生类仍然是抽象类,仍然不能实例化,只有给出了全部纯虚函数的实现,派生类才不再是抽象类并且才可以实例化。
我们不能声明抽象类的对象,使用抽象类一般是通过声明抽象类的指针或引用,将指针或引用指向派生类的对象,访问派生类的成员。
程序如下:
#include <iostream>
using namespace std;
class Base // 抽象类Base的声明
{
public:
virtual void show() = 0; // 纯虚函数成员show
};
class Child0 : public Base // 类Base的公有派生类Child0的声明
{
public:
void show() { cout << "Child0::show()" << endl; } // 虚成员函数show
};
class Child1 : public Child0 // 类Child0的公有派生类Child1的声明
{
public:
void show() { cout << "Child1::show()" << endl; } // 虚成员函数show
};
void CallShow(Base *pBase) // 一般函数,参数为基类指针
{
pBase->show();
}
int main()
{
Base *pBase; // 声明Base类的指针
Child0 ch0; // 声明Child0类的对象
Child1 ch1; // 声明Child1类的对象
pBase = &ch0; // 将Child0类对象ch0的地址赋值给Base类指针pBase
CallShow(pBase);
pBase = &ch1; // 将Child1类对象ch1的地址赋值给Base类指针pBase
CallShow(pBase);
return 0;
}程序运行结果为:
Child0::show()
Child1::show()这里派生类Child0和Child1的虚函数show并没有使用关键字virtual显式说明,因为Child0和Child1中的虚函数和基类Base中的纯虚函数名称一样,参数和返回值都相同,编译器会自动识别其为虚函数。
上面的程序中,基类Base是抽象类,为整个类族提供了统一的外部接口。派生类Child0中给出了全部纯虚函数的实现(其实只有一个纯虚函数--show),因此不再是抽象类,可以声明它的对象。Child0的派生类Child1当然也不是抽象类。根据赋值兼容规则,基类Base的指针可以指向派生类Child0和Child1的对象,通过此指针可以访问派生类的成员,这样就实现了多态。
参考:
更多相关内容 -
纯虚函数和抽象类
2020-02-24 16:42:33而纯虚函数也和虚函数一样,用virtual来修饰的类的成员函数,但是只能有函数体不能有具体实现。 一般格式: class <类名> { virtual <类型><函数名>(<参数表>) = 0; ... } 1...什么是纯虚函数
纯虚函数是一种特殊的虚函数,前面分析过虚函数,虚函数是virtual修饰的类的成员函数,可以有实现。而纯虚函数也和虚函数一样,用virtual来修饰的类的成员函数,但是只能有函数体不能有具体实现。
一般格式:
class <类名> { virtual <类型><函数名>(<参数表>) = 0; ... }
1、纯虚函数是一个在父类中只有函数体,没有实现,实现在子类中去完成
2、纯虚函数为各子类提供了一个公共界面(接口的封装和设计、软件的模块功能划分)
3、一个具有纯虚函数的父类也称为抽象类
为什么要用到纯虚函数(抽象类)
1、为了方便使用多态特性
2、在很多情况下,父类本身生成对象是不合理的。例如,动物作为一个父类可以派生出猫、狗等子类,但动物本身生成对象明显不合理。
#pragma warning(disable : 4996) #include <iostream> using namespace std; class Animal { public: Animal() { this->m_a = 1; cout << "Animal: 构造函数" << endl; } ~Animal() {} virtual void Call() { cout << "Animal: Call" << endl; } virtual void Eat() = 0; private: int m_a; }; class Cat:public Animal { public: Cat() { this->m_a = 2; cout << "Cat: 构造函数" << endl; } ~Cat() {} virtual void Call() { cout << "Cat: Call" << endl; } void Eat() { cout << "Cat: Eat" << endl; } private: int m_a; }; //不允许使用抽象类作函数参数 //void Test(Animal a){} int main() { //Animal a1;//不允许使用抽象类类型 //Animal a2();//不允许返回抽象类 //Test(a1);//不允许使用抽象类作函数参数 Animal *a = new Cat(); a->Call(); a->Eat(); Cat c; Animal &a1 = c; a1.Call(); a1.Eat(); printf("父类占内存大小:%d, 子类占内存大小:%d\n", sizeof(Animal), sizeof(Cat)); system("pause"); return 0; }
如上面的例子,我们可以总结对抽象类做哪些操作是合理的:
1、可以声明抽象类的指针:Animal *cat = new Cat();
2、可以声明抽象类的引用:Animal &cat
抽象类在多继承中的应用
C++中没有接口这个概念,学过其他高级语言的朋友可能接触过了接口(协议)这个概念,那么C++中的抽象类就是模拟的这种机制。但是在继承中高级语言不能继承多个父类,可以继承多个接口,C++中没有接口这个概念,但可以继承多个类,那就是多继承概念。
绝大多数面向对象语言都不支持多继承,绝大多数面向对象语言都支持接口的概念,C++中没有接口的概念,C++中可以使用纯虚函数实现接口,接口类中只有函数原型定义,没有任何数据的定义。
class Interface1 { public: virtual void print() = 0; virtual int add(int a, int b) = 0; }; class Interface2 { public: virtual void print() = 0; virtual int add(int a, int b) = 0; virtual int minus(int a, int b) = 0; }; class parent { public: int a; }; class Child : public parent, public Interface1, public Interface2 { public: void print() { cout << "Child::print" << endl; } int add(int a, int b) { return a + b; } int minus(int a, int b) { return a - b; } }; int main() { Child c; c.print(); cout << c.add(3, 5) << endl; cout << c.minus(4, 6) << endl; Interface1* i1 = &c; Interface2* i2 = &c; cout << i1->add(7, 8) << endl; cout << i2->add(7, 8) << endl; system("pause"); return 0; }
由上面的例子可以得出:
- 多重继承接口不会带来二义性和复杂性等问题
- 多重继承可以通过精心设计用单继承和接口来代替
- 接口类只是一个功能说明,而不是功能实现。
- 子类需要根据功能说明定义功能实现。
-
C++:纯虚函数和抽象类 | 虚函数和纯虚函数区别
2022-03-30 10:42:15纯虚函数和抽象类 虚函数和纯虚函数区别前言
本文由纯虚函数和抽象类引出工厂模式,继承与多态的内容到达本篇,也基本介绍完了。
纯虚函数概念
纯虚函数(pure virtual function)是指被标明为不具体实现的虚拟成员函数。它用于这样的情况:定义一个基类时,会遇到无法定义基类中虚函数的具体实现,其实现依赖于不同的派生类。
定义纯虚函数的一般格式为:
virtual 返回类型 函数名(参数列表) = 0;
“=0”表明程序员将不定义该函数,函数声明是为派生类保留一个位置。“=0”本质上是将指向函数体的指针定为NULL。
抽象类的概念
首先要了解到:含有纯虚函数的基类是不能用来定义对象的。
纯虚函数没有实现部分,不能产生对象,所以含有纯虚函数的类是抽象类。-
带有纯虚函数的类称为抽象类。抽象类是一种特殊的类,它是为了抽象和设计的目的而建立的,它处于继承层次结构的较上层。抽象类是不能定义对象的,在实际中为了强调一个类是抽象类,可将该类的构造函数说明为保护的访问控制权限。
-
抽象类的主要作用是将有关的组织在一个继承层次结构中,由它来为它们提供一个公共的根,相关的子类是从这个根派生出来的。
-
抽象类刻画了一组子类的操作接口的通用语义,这些语义也传给子类。一般而言,抽象类只描述这组子类共同的操作接口,而完整的实现留给子类。
-
抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类没有重新定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体类了。
示例
实在不理解抽象类,那么可以这样想:
面向对象设计的类,其目的是为了模拟现实,普通的类意思就是,可以模拟实现动物,家具等具体事物;那么抽象类所模拟的示例有:社会,生活,打工等。
比如有人说,C++太难了,我还是去工地搬砖吧,这样的行为可以用普通的类模拟,设计出搬砖这种类;但有人说,C++太难了,我不学了想去混社会,这个就无法模拟实现出来了,所以就叫做抽象类。类的分类
在经过继承和多态的学习后,可以总结出类可以分为下面这些:
普通类
有数据,有方法的类
class Object { private: string name; public: void Print()const {} };
继承,有虚函数的类
在继承中基类有虚函数,派生类实现基类虚方法,程序运行时产生动态联编的情况
class Object { private: string name; public: virtual void Print()const {} }; class Base : public Object { private: int num; public: virtual void Print()const {} };
抽象类
基类中有纯虚函数,派生类必须实现基类的纯虚函数的情况,称为抽象类。
class Object { private: string name; public: void add() {} virtual void Print()const = 0; }; class Base : public Object { private: int num; public: virtual void Print()const { cout << "..." << endl; } };
interface(接口)
在一个抽象类中,只有方法类的集合,即只有纯虚函数的类叫做interface。
在派生类中,必须要重写所有的方法,不然这个派生类也是抽象类。struct Object { virtual void Print() = 0; virtual void Add() = 0; virtual void fun() = 0; };
总结
抽象类的规定
(1)抽象类只能用作其他类的基类,不能建立抽象类对象。
(2)抽象类不能用作参数类型、函数返回类型或显式转换的类型。
(3)可以定义指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性。虚函数和纯虚函数区别
-
类里如果声明了虚函数,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数在它的子类里面可以被覆盖,这样的话,这样编译器就可以使用后期绑定来达到多态了。纯虚函数只是一个接口,是个函数的声明而已,它要留到子类里去实现。
-
虚函数在子类里面也可以不重载的;但纯虚函数必须在子类去实现,这就像Java的接口一样。通常把很多函数加上virtual,是一个好的习惯,虽然牺牲了一些性能,但是增加了面向对象的多态性,因为很难预料到父类里面的这个函数不在子类里面不去修改它的实现。
-
带纯虚函数的类叫虚基类,这种基类不能直接生成对象,而只有被继承,并重写其虚函数后,才能使用。这样的类也叫抽象类。抽象类和大家口头常说的虚继承基类还是有区别的,在C#中用abstract定义抽象类,而在C++中有抽象类的概念,但是没有这个关键字。抽象类被继承后,子类可以继续是抽象类,也可以是普通类。
虚基类:“virtual”继承的类,也就是说任何类都可以成为虚基类。
抽象类:至少包含一个纯虚函数的类,其不能被实例化,哪怕该纯虚函数在该类中被定义。二者没有任何联系。虚基类就是解决多重多级继承造成的二义性问题。
-
-
C++——抽象类之纯虚函数和实现抽象类中的成员函数
2021-06-14 21:58:40包含有纯虚函数的类称为抽象类,一个抽象类至少具有一个纯虚函数。抽象类只能作为基类派生出的新的子类,而不能在程序中被实例化(即不能说明抽象类的对象...许多情况下,在基类中不能给虚函数一个有意义的定义,这时可包含有纯虚函数的类称为抽象类,一个抽象类至少具有一个纯虚函数。抽象类只能作为基类派生出的新的子类,而不能在程序中被实例化(即不能说明抽象类的对象),但是可以使用指向抽象类的指针。像在开发程序的过程中,并不是所有代码都是由软件构造师自己写的,有时候需要调用库函数,有时候分给别人来写。一名软件构造师可以通过纯虚函数建立接口,然后让程序员填写代码实现接口,而自己主要负责建立抽象类。
纯虚函数
纯虚函数是指被标明为不具体实现的虚成员函数,它不具备函数的功能。
许多情况下,在基类中不能给虚函数一个有意义的定义,这时可以在基类中将它说明为纯虚函数,而其实现留给派生类去做。纯虚函数不能被直接调用,仅起到提供一个与派生类相一致的接口的作用。
声明纯虚函数的形式如下:
virtual 类型 函数名(参数列表)=0;
纯虚函数不可以被继承。当基类是抽象类时,在派生类中必须给出基类中纯虚函数的定义,或者在该类中再声明其为纯虚函数。只有在派生类中给出了基类中所有纯虚函数的实现时,该派生类才不再成为抽象类。例子:
创建纯虚函数#include<iostream> using namespace std; class Figure { public: virtual double getArea() = 0; }; const double PI = 3.14; class Circle:public Figure { private: double Radius; public: Circle(double R) { Radius = R; } double getArea() { return Radius * Radius * PI; } }; class Rectangle:public Figure { protected: double Height,Width; public: Rectangle(double height,double width) { Height = height; Width = width; } double getArea() { return Height * Width; } }; int main() { Figure *fg1; fg1 = new Rectangle(4.0,5.0); cout << fg1->getArea() << endl; delete fg1; Figure *fg2; fg2 = new Circle(4.0); cout << fg2->getArea() << endl; delete fg2; return 0; }
注意:
对于包含纯虚函数的类来说,是不能够实例化的,“Figure figure;”是错误的。
结果:
程序定义了矩形类Rectangle和圆形类Circle,两个类都派生于图形类Figure。图形类是一个在现实生活中不存在的对象,抽象类面积的计算方法不确定,所以,将图形类Figure的面积计算方法设置为纯虚函数,这样圆形有圆形面积的计算方法,矩形有矩形面积的计算方法,每个继承自Figure的对象都有自己的面积,通过getArea成员函数就可以获取面积值。实现抽象类中的成员函数
抽象类通常用于作为其他类的父类,从抽象类派生的子类如果不是抽象类,则子类必须实现父类中的所有纯虚函数。
例子:
#include<iostream> using namespace std; class CEmployee { public: int m_ID; char m_Name[128]; char m_Depart[128]; virtual void OutputName() = 0; //定义抽象成员函数 }; class COperator:public CEmployee { public: char m_Password[128]; void OutputName() //实现父类中的纯虚成员函数 { cout << "Operator's name:" << m_Name << endl; } COperator() { strcpy(m_Name,"Johnson"); } }; class CSystemManager:public CEmployee { public: char m_Password[128]; void OutputName() //实现父类中的纯虚成员函数 { cout << "SystemManager's name:" << m_Name << endl; } CSystemManager() { strcpy(m_Name,"Johnson666"); } }; int main() { CEmployee *pWorker; pWorker = new COperator(); pWorker->OutputName(); delete pWorker; pWorker = NULL; pWorker = new CSystemManager(); pWorker->OutputName(); delete pWorker; pWorker = NULL; return 0; }
结果:
程序中从CEmployee类派生了两个子类,分别为COperator和CSystemManager。这两个类分别实现了父类的纯虚成员函数OutputName。同样的一条语句“pWorker->OutputName();”,由于pWorker指向的对象不同,其行为也不同。 -
c++抽象类中纯虚函数的理解
2019-11-21 22:15:35纯虚函数:纯虚函数就在基类中只是定义并不实现,需要...抽象类:一个类中含有一个或者多个纯虚函数,那么这个类就是抽象类。不能实例化对象,只能定义指针,指向派生类以实现多态。 代码示例: // ConsoleAppli... -
C++中虚函数与纯虚函数的用法
2020-09-04 06:37:09主要介绍了C++中虚函数与纯虚函数的用法,是非常重要的概念,需要的朋友可以参考下 -
纯虚函数与抽象类
2021-05-19 15:26:53纯虚函数与抽象类纯虚函数,就是没有...包含纯虚函数的类就是抽象类,一个抽象类至少有一个纯虚函数。抽象类的存在是为了提供一个高度抽象、对外统一的接口,然后通过多态的特性使用各自的不同方法,是C++面向对象... -
C++ 纯虚函数(抽象类)
2020-02-17 15:55:44含有纯虚函数的类是抽象类,不能生成对象,只能派生。他派生的类的纯虚函数没有被改写,那么,它的派生类还是个抽象类。 -
c++ 虚函数与纯虚函数的区别(深入分析)
2021-01-20 06:59:48那么,什么是虚函数呢,我们先来看看微软的解释: 虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。 -
C++之纯虚函数与抽象类
2021-08-04 20:49:05C++之纯虚函数与抽象类什么是纯虚函数?什么是抽象类 什么是纯虚函数? 纯虚函数是将基类中的函数声明为虚函数=0的函数。纯虚函数只能声明,不能定义,因为纯虚函数没有函数体。纯虚函数的写法为 virtual 函数返回... -
什么是抽象类?什么是纯虚函数?纯虚函数跟一般的虚函数有什么区别?
2020-03-15 10:20:54纯虚函数: 一个函数只有函数名和形参列表,没有具体实现;语法:virtual double GetArea()=0; 抽象类: 在C++中,含有纯虚拟函数的类称为抽象类,它不能生成对象。抽象类是不完整的,它只能用作基类。 含有纯虚... -
C++(十五)虚函数和纯虚函数(抽象类)
2020-02-29 15:14:50文章目录一、虚函数二、虚析构函数 一、虚函数 ...下面的类 A 就是一个抽象类: class A { private: int a; public: virtual void Print() = 0; //纯虚函数 void fun1() { cout << "fun1";... -
什么是纯虚函数?什么是抽象类?
2020-04-11 17:38:13纯虚函数: 一个函数只有函数名和形参列表,没有具体实现;语法:virtual double GetArea()=0; 抽象类: 在C++中,含有纯虚拟函数的类称为抽象类,它不能生成对象。抽象类是不完整的,它只能用作基类。 含有纯虚... -
虚函数,多态,纯虚函数、抽象类
2021-12-27 09:19:38纯虚函数 -
C++抽象类详解--纯虚函数,抽象类
2018-07-03 17:03:35在介绍抽象类之前,我们先介绍一下纯虚函数。1.纯虚函数 在基类中仅仅给出声明,不对虚函数实现定义,而是在派生类中实现。这个虚函数称为纯虚函数。普通函数如果仅仅给出它的声明而没有实现它的函数体,这是编译... -
C++抽象类和纯虚函数
2021-04-14 01:43:03在继承层次结构中,有一项很方便的做法,可以在基类中定义一个成员函数,该函数只能在每个派生类中实现,而不能由基类本身来实现,因为合理实现所需的细节只能在派生类中找到。如果是这种情况,那么 C++ 语言允许... -
【C++快速上手】七、纯虚函数和抽象类学习笔记
2020-08-17 11:51:28抽象类只能作为基类来派生新类使用,不能创建抽象类的对象,可以创建抽象类的指针和引用。 抽象类中:在成员函数内可以调用纯虚函数,在构造函数/析构函数内部不能使用纯虚函数。 如果一个类从抽象类派生而来,它... -
C++纯虚函数和派生类用法(抽象基类ABC)
2019-07-02 23:15:40C++中,如果希望有一个公共基类只声明一个函数接口,在该公共基类不进行定义,而是在派生类才重新定义;重新定义时,不同的派生类重新定义不同的功能,则这种情况下,最好使用C++的纯虚函数和派生类。(最后面有源... -
c++5.5纯虚函数和抽象类
2021-04-17 10:46:59纯虚函数 如果不能在基类中给出有意义的虚函数的实现,但又必须让基类为派生类提供一个公共界面函数,这时可将其声明为...一个抽象类只能作为基类来派生新类,不能说明抽象类的对象。 Figure fig;//不能说明抽象类的 -
C++继承详解(三):抽象类和纯虚函数、多重继承与虚基类的底层实现原理详解
2019-04-23 03:27:29纯虚函数 、抽象类 、多重继承 、二义性问题 、菱形继承 、虚基类 、从内存布局看虚继承的底层实现原理 -
《随笔十二》—— C++中的 “ 纯虚函数 和 抽象类 ”
2018-11-27 11:48:59目录 抽象类 纯虚函数 抽象类 ● 抽象类: 不用于定义对象而只作为一种基本类型用做继承的类... 我们在实际中为了强调一个类是抽象类, 可将该类的构造函数声明为 保护的访问控制权限, 这样我们就不能 在类外... -
C++ 中纯虚函数与抽象基类
2021-01-13 14:35:471. 纯虚函数定义 纯虚函数是在基类中声明的一个虚函数,它在基类中没有定义,但要求所有继承该基类的派生类都要实现该...含有纯虚函数的类为抽象类,抽象类不能创建自己的对象,只能创建它的派生类的对象 3. 为什么