C++简单春虚函数的应用
- 格式:doc
- 大小:31.00 KB
- 文档页数:4
虚函数原理虚函数是 C++ 中一个非常重要的特性,它为面向对象编程提供了很强的支持。
虚函数的实现原理是通过虚函数表实现的,本文将介绍虚函数的概念、使用方法以及实现原理。
一、虚函数概念虚函数是指在基类中使用 virtual 关键字声明的成员函数,它的作用是允许在子类中对该函数进行覆盖。
具体来说,虚函数允许在子类中定义一个与基类中同名的函数,当使用子类对象调用该函数时,程序会动态的选择调用子类中的函数。
虚函数的语法如下:```class Base {public:virtual void foo();};```虚函数可以被重写(覆盖),也可以被继承,但是不能被 static 和 friend 修饰。
二、虚函数的使用使用虚函数需要满足一下条件:1.虚函数必须在公有的类成员函数列表中声明,并在类声明的内部定义。
2.虚函数必须在基类和派生类中以相同的参数列表进行定义。
下面是一个使用虚函数的简单例子:class Square: public Shape {public:Square(double s) : side(s) {}double getArea() { return side * side; }Shape 是一个基类,Square 是它的一个派生类,Square 中重写了 getArea() 函数,计算正方形的面积。
虚函数的实现原理是通过虚函数表实现的。
虚函数表是一个指针数组,存储了每个类中的虚函数指针。
当对象被创建时,会在其内存空间中创建一个指向虚函数表的指针,这个指针通常称为虚函数表指针(vptr),虚函数的调用就是通过这个指针完成的。
每个含有虚函数的类都有一个独立的虚函数表,虚函数表智能在类的第一个对象中存储,它包含了该类中所有虚函数的地址。
在派生类中,虚函数表通常继承自它的直接基类,并在此基础上添加或修改虚函数的地址。
这样如果在派生类对象中调用虚函数时,程序会先获得对象的虚函数表指针,然后通过该指针找到对应的虚函数地址来执行函数。
虚函数定义虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public,在基类的类定义中定义虚函数的一般形式:virtual 函数返回值类型虚函数名(形参表){ 函数体}作用虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。
以实现统一的接口,不同定义过程。
如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。
当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。
动态联编规定,只能通过指向基类的指针或基类对象的引用来调用虚函数,其格式:指向基类的指针变量名->虚函数名(实参表)或基类对象的引用名. 虚函数名(实参表)虚函数是C++多态的一种表现例如:子类继承了父类的一个函数(方法),而我们把父类的指针指向子类,则必须把父类的该函数(方法)设为virturl(虚函数)。
使用虚函数,我们可以灵活的进行动态绑定,当然是以一定的开销为代价。
如果父类的函数(方法)根本没有必要或者无法实现,完全要依赖子类去实现的话,可以把此函数(方法)设为virturl 函数名=0 我们把这样的函数(方法)称为纯虚函数。
如果一个类包含了纯虚函数,称此类为抽象类。
示例虚函数的实例:#include<iostream.h>class Cshape{public:void SetColor( int color) { m_nColor=color;}void virtual Display( void) { cout<<"Cshape"<<endl; }private:int m_nColor;};class Crectangle: public Cshape{public:void virtual Display( void) { cout<<"Crectangle"<<endl; } };class Ctriangle: public Cshape{void virtual Display( void) { cout<<"Ctriangle"<<endl; }};class Cellipse :public Cshape{public: void virtual Display(void) { cout<<"Cellipse"<<endl;} };void main(){Cshape obShape;Cellipse obEllipse;Ctriangle obTriangle;Crectangle obRectangle;Cshape * pShape[4]=for( int I= 0; I< 4; I++)pShape[I]->Display( );}本程序运行结果:CshapeCellipseCtriangleCrectangle所以,从以上程序分析,实现动态联编需要三个条件:1、必须把动态联编的行为定义为类的虚函数。
虚函数是C++中的一个非常重要的概念,它允许我们在派生类中重新定义基类中的函数,从而实现多态性。
在本文中,我们将深入探讨virtual关键字的作用,以及virtual函数和纯虚函数的使用方法。
在C++中,virtual关键字用于声明一个虚函数。
这意味着当派生类对象调用该函数时,将会调用其在派生类中的定义,而不是基类中的定义。
这种行为使得我们能够在派生类中定制化地实现函数的逻辑,从而实现不同对象的不同行为。
对于virtual函数,我们需要注意以下几点:1. 在基类中声明函数时,使用virtual关键字进行声明。
2. 派生类中可以选择性地使用virtual关键字进行重声明,但通常最好也使用virtual,以便明确表明这是一个虚函数。
3. 当使用派生类对象调用虚函数时,将会根据对象的实际类型调用适当的函数实现。
4. 虚函数的实现通过虚函数表(vtable)来实现,这是一张函数指针表,用于存储各个虚函数的位置区域。
除了普通的虚函数外,C++还提供了纯虚函数的概念。
纯虚函数是在基类中声明的虚函数,它没有函数体,只有声明。
这意味着基类不能直接实例化,只能用作其他类的基类。
纯虚函数通常用于定义一个接口,而具体的实现则留给派生类。
接下来,让我们以一个简单的例子来说明虚函数和纯虚函数的用法。
假设我们有一个基类Shape,它包含一个纯虚函数calcArea用于计算面积。
有两个派生类Circle和Rectangle,它们分别实现了calcArea 函数来计算圆形和矩形的面积。
在这个例子中,我们可以看到基类Shape定义了一个纯虚函数calcArea,它没有函数体。
而派生类Circle和Rectangle分别实现了这个函数来计算不同形状的面积。
当我们使用Shape指针指向Circle或Rectangle对象时,调用calcArea函数将会根据对象的实际类型来调用适当的实现。
除了虚函数和纯虚函数外,C++中还有虚析构函数的概念。
c语言常用函数大全及详解C语言是一种通用的、面向过程的编程语言,被广泛应用于系统软件、嵌入式开发以及科学计算领域。
在C语言中,函数是一种模块化编程的基本方法,通过函数可以将一段代码进行封装和复用,提高了代码的可读性和可维护性。
本文将介绍一些C语言中常用的函数,并详细解释其用法及重要参数。
一、数学函数1. abs()函数函数原型:int abs(int x);函数功能:返回x的绝对值。
参数说明:x为一个整数。
2. pow()函数函数原型:double pow(double x, double y);函数功能:计算x的y次方。
参数说明:x和y为两个double类型的实数。
3. sqrt()函数函数原型:double sqrt(double x);函数功能:计算x的平方根。
参数说明:x为一个double类型的实数。
二、字符串函数1. strcpy()函数函数原型:char* strcpy(char* destination, const char* source);函数功能:将source字符串复制到destination字符串。
参数说明:destination为目标字符串,source为源字符串。
2. strlen()函数函数原型:size_t strlen(const char* str);函数功能:计算str字符串的长度。
参数说明:str为一个以'\0'结尾的字符串。
3. strcat()函数函数原型:char* strcat(char* destination, const char* source);函数功能:将source字符串拼接到destination字符串的末尾。
参数说明:destination为目标字符串,source为源字符串。
三、文件操作函数1. fopen()函数函数原型:FILE* fopen(const char* filename, const char* mode);函数功能:打开一个文件,并返回文件指针。
纯虚函数空函数一、纯虚函数纯虚函数是指在基类中声明但没有定义的虚函数,它的作用是为派生类提供一个接口,派生类必须实现这个函数。
纯虚函数的声明语法为:virtual 返回类型函数名(参数列表) =0;其中“=0”表示该函数为纯虚函数。
纯虚函数的特点:1.没有函数体。
在基类中声明但没有提供函数的具体实现,从而使得基类成为了抽象类,不能被实例化。
2.继承。
子类必须实现纯虚函数,否则也将成为抽象类,无法被实例化。
3.多态性。
子类中实现了基类的纯虚函数后,可以通过基类指针调用子类的实现。
1.抽象类。
基类中有至少一个纯虚函数时,该基类就成为了抽象类。
抽象类不能被实例化,只能被其他类继承和实现。
2.接口。
纯虚函数提供了一种接口,规定了子类必须实现的方法。
这种方法被称为“接口”。
让我们创建一个基类Figure,定义一个纯虚函数area(),用于计算图形的面积。
代码如下:class Figure{public:virtual double area() = 0;};class Circle : public Figure{public:Circle(double r){radius = r;}double area(){return 3.1415926 * radius * radius; // 计算圆的面积}private:double radius;};使用上述代码创建一个程序,可以通过基类指针调用子类实现的结果。
代码如下:以上程序会输出圆的面积,结果如下:Circle's area is:314.15926二、空函数空函数是指没有任何实际功能的函数,用于占位或在后续开发中替换为有用的函数。
空函数的定义语法为:void 函数名(){}1.通常没有函数体,函数体中只有一个空语句,表示不需要执行任何操作。
2.占位。
空函数可以用作占位函数来占据函数列表中的某些位置,等待日后补充功能。
3.代码兼容性。
空函数可以提高代码的兼容性,当代码需要调用某个函数时,即使函数还未完成,也可以使用空函数来代替。
纯虚构造函数纯虚构造函数是指在抽象类中定义的没有实现的构造函数。
它的作用是强制子类在实现自己的构造函数时必须调用父类的构造函数,从而确保父类的成员变量被正确地初始化。
在C++中,纯虚构造函数的语法如下:```class A {public:virtual A() = 0;};```需要注意的是,纯虚构造函数不能被实例化,因此它的实现必须由子类来完成。
子类必须在自己的构造函数中调用父类的构造函数,否则编译器会报错。
纯虚构造函数的使用场景主要是在抽象类中。
抽象类是指不能被实例化的类,它的作用是为了让子类继承它的接口和实现。
抽象类中定义的纯虚函数和纯虚构造函数都没有实现,因此子类必须实现它们才能被实例化。
下面是一个简单的例子,演示了如何使用纯虚构造函数:```class Shape {public:virtual Shape() = 0;virtual double area() = 0;};class Circle : public Shape {public:Circle(double r) {radius = r;}double area() {return 3.14 * radius * radius;}private:double radius;};class Rectangle : public Shape {public:Rectangle(double w, double h) {width = w;height = h;}double area() {return width * height;}private:double width;double height;};int main() {Circle c(2.0);Rectangle r(3.0, 4.0);cout << "Circle area: " << c.area() << endl;cout << "Rectangle area: " << r.area() << endl; return 0;}```在上面的例子中,Shape是一个抽象类,它定义了纯虚构造函数和纯虚函数area()。
纯虚函数是一种在基类中声明但不定义的虚函数,它的作用是要求派生类必须实现该函数。
纯虚函数的使用场景通常是在设计抽象类或接口时,用来规定派生类必须实现的方法,以实现多态性。
以下是一些纯虚函数的使用场景:抽象类定义接口:当需要定义一个抽象类来定义接口时,可以使用纯虚函数来实现。
这样,任何派生类都必须实现这些纯虚函数,以实现接口。
强制派生类实现特定方法:有时候,某些方法在派生类中必须实现,但基类中并没有具体的实现。
在这种情况下,可以使用纯虚函数来强制派生类实现该方法。
实现多态性:纯虚函数是实现多态性的重要手段之一。
通过在基类中声明纯虚函数,可以让派生类实现该函数,从而实现多态性。
总之,纯虚函数的使用场景是在需要定义接口、强制派生类实现特定方法或实现多态性时使用。
C++之普通成员函数、虚函数以及纯虚函数的区别与⽤法要点普通成员函数是静态编译的,没有运⾏时多态,只会根据指针或引⽤的“字⾯值”类对象,调⽤⾃⼰的普通函数;虚函数为了重载和多态的需要,在基类中定义的,即便定义为空;纯虚函数是在基类中声明的虚函数,它可以再基类中有定义,且派⽣类必须定义⾃⼰的实现⽅法。
假设我们有三个类Person、Teacher、Student它们之间的关系如下:类的关系图普通成员函数【Demo1】根据这个类图,我们有下⾯的代码实现#ifndef __OBJEDT_H__#define __OBJEDT_H__#include <string>#include <iostream>class Person{public:Person(const string& name, int age) : m_name(name), m_age(age){}void ShowInfo(){cout << "姓名:" << m_name << endl;cout << "年龄:" << m_age << endl;}protected:string m_name; //姓名int m_age; //年龄};class Teacher : public Person{public:Teacher(const string& name, int age, const string& title): Person(name, age), m_title(title){}void ShowInfo(){cout << "姓名:" << m_name << endl;cout << "年龄:" << m_age << endl;cout << "职称:" << m_title << endl;}private:string m_title; //职称};class Student : public Person{public:Student(const string& name, int age, int studyId): Person(name, age), m_studyId(studyId){}void ShowInfo(){cout << "姓名:" << m_name << endl;cout << "年龄:" << m_age << endl;cout << "学号:" << m_studyId << endl;}private:int m_studyId; //学号};#endif //__OBJEDT_H__测试代码:void test(){Person* pPerson = new Person("张三", 22);Teacher* pTeacher = new Teacher("李四", 35, "副教授");Student* pStudent = new Student("王五", 18, 20151653);pPerson->ShowInfo();cout << endl;pTeacher->ShowInfo();cout << endl;pStudent->ShowInfo();cout << endl;delete pPerson;delete pTeacher;delete pStudent;}结果:姓名:张三年龄:22姓名:李四年龄:35职称:副教授姓名:王五年龄:18学号:20151653说明:这⾥的ShowInfo就是⼀个普通的函数。
c语言中所有函数用法在C语言中,函数是程序的基本构建块之一。
以下是C语言中一些常见的函数用法:1. 函数的定义:```c// 函数原型声明int add(int a, int b);// 函数定义int add(int a, int b) {return a + b;}```2. 函数的调用:```cint result = add(3, 4);```3. 函数参数传递方式:-按值传递:```cvoid modifyValue(int x) {x = 10;}int main() {int num = 5;modifyValue(num);// num 的值仍然是5,因为modifyValue 中的修改不影响原始值return 0;}```-按引用传递:```cvoid modifyValue(int *x) {*x = 10;}int main() {int num = 5;modifyValue(&num);// num 的值现在是10,因为modifyValue 中通过指针修改了原始值return 0;}```4. 函数返回值:```cint add(int a, int b) {return a + b;}int main() {int result = add(3, 4);// result 的值为7return 0;}```5. 函数多参数:```cfloat calculateAverage(int num1, int num2, int num3) {return (num1 + num2 + num3) / 3.0;}int main() {float avg = calculateAverage(10, 20, 30);// avg 的值为20.0return 0;}```6. 函数重载(C语言不支持函数重载):C语言本身不支持函数重载。
如果你需要实现类似功能,可以使用不同的函数名或者使用默认参数。
C++使⽤纯虚函数和单例模式导出接⼝的动态库的写法要写⼀个C++的动态库,⾥⾯每个函数都要共⽤到⼀个变量。
我觉得这样最好写成类的形式,该变量就可以作为类的成员变量来封装。
但我不希望将整个类都导出,希望只导出特定的接⼝函数。
于是我想到了继承,让⼦类继承⽗类(纯虚函数类)。
另外,使⽤了单例模式。
最后只导出获取单例的函数即可。
⽗类接⼝函数头⽂件:#pragma once#define DLL_API _declspec(dllexport)const int OPER_SUCCESS = 0;const int DEV_NOT_CONN = -1;const int INPT_WRONG = -2;class CFluke5500aOperInterface{public:virtual int open_fluke5500a_conn(const char* const rsrc_name) = 0;virtual int close_fluke5500a_conn() = 0;virtual int cmd_oper() = 0;virtual int cmd_rst() = 0;virtual int cmd_out_ma(int ma) = 0;virtual int send_cmd(const char* const str_cmd) = 0;virtual int cmd_stby() = 0;virtual int cmd_clear_all_stat() = 0;};⼦类头⽂件:#pragma once#include "fluke5500a_gpib_interface.h"#include "include\visa.h"#include "include\visatype.h"class CFluke5500aOper : public CFluke5500aOperInterface{public:~CFluke5500aOper(void);CFluke5500aOper(const CFluke5500aOper&) = delete;CFluke5500aOper& operator=(const CFluke5500aOper&) = delete;static CFluke5500aOper& get_inst();int open_fluke5500a_conn(const char* const rsrc_name);int close_fluke5500a_conn();int cmd_oper();int cmd_rst();int cmd_out_ma(int ma);int send_cmd(const char* const str_cmd);int cmd_stby();int cmd_clear_all_stat();private:CFluke5500aOper();ViSession m_vi_session_rm;ViSession m_vi_session;/** 同步互斥,临界区保护 */CRITICAL_SECTION m_cs_communication_sync;};类的实现⽂件(注意只在获取单例的函数这⾥添加了导出:extern "C" DLL_API CFluke5500aOperInterface& get_fluke5500a_oper()):#include "pch.h"#include "fluke5500a_gbip_com.h"#include <stdio.h>#include <stdlib.h>#include <string>#pragma comment(lib, "lib\\visa32.lib")extern"C" DLL_API CFluke5500aOperInterface& get_fluke5500a_oper(){return CFluke5500aOper::get_inst();}CFluke5500aOper& CFluke5500aOper::get_inst(){static CFluke5500aOper instance;return instance;}CFluke5500aOper::CFluke5500aOper(){InitializeCriticalSection(&m_cs_communication_sync);m_vi_session_rm = NULL;m_vi_session = NULL;}CFluke5500aOper::~CFluke5500aOper(void){DeleteCriticalSection(&m_cs_communication_sync);}int CFluke5500aOper::open_fluke5500a_conn(const char* const rsrc_name){/*进⼊临界段*/EnterCriticalSection(&m_cs_communication_sync);ViStatus ret = viOpenDefaultRM(&m_vi_session_rm);if (ret != VI_SUCCESS){viClose(m_vi_session_rm);/*离开临界段*/LeaveCriticalSection(&m_cs_communication_sync);return ret;}ret = viOpen(m_vi_session_rm, rsrc_name, VI_EXCLUSIVE_LOCK, VI_NULL, &m_vi_session);if (ret != VI_SUCCESS){viClose(m_vi_session);viClose(m_vi_session_rm);/*离开临界段*/LeaveCriticalSection(&m_cs_communication_sync);return ret;}/*离开临界段*/LeaveCriticalSection(&m_cs_communication_sync);return OPER_SUCCESS;}int CFluke5500aOper::close_fluke5500a_conn(){/*进⼊临界段*/EnterCriticalSection(&m_cs_communication_sync);ViStatus ret = viClose(m_vi_session);if (ret != VI_SUCCESS){/*离开临界段*/LeaveCriticalSection(&m_cs_communication_sync);return ret;}ret = viClose(m_vi_session_rm);if (ret != VI_SUCCESS){/*离开临界段*/LeaveCriticalSection(&m_cs_communication_sync);return ret;}/*离开临界段*/LeaveCriticalSection(&m_cs_communication_sync);return OPER_SUCCESS;}int CFluke5500aOper::cmd_oper(){return send_cmd("OPER\n");}int CFluke5500aOper::cmd_rst(){return send_cmd("*RST\n");}int CFluke5500aOper::cmd_clear_all_stat(){return send_cmd("*CLS\n");}int CFluke5500aOper::cmd_stby(){return send_cmd("STBY\n");}int CFluke5500aOper::cmd_out_ma(int ma){if (ma < 0){return INPT_WRONG;}char str_ma[36];sprintf_s(str_ma, "%d", ma);std::string str_cmd = "OUT ";str_cmd.append(str_ma);str_cmd.append("MA\n");return send_cmd(str_cmd.c_str());}int CFluke5500aOper::send_cmd(const char* const str_cmd){/*进⼊临界段*/EnterCriticalSection(&m_cs_communication_sync);if (m_vi_session == NULL) {/*离开临界段*/LeaveCriticalSection(&m_cs_communication_sync);return DEV_NOT_CONN;}ViStatus ret = viPrintf(m_vi_session, str_cmd);if (ret != VI_SUCCESS){/*离开临界段*/LeaveCriticalSection(&m_cs_communication_sync);return ret;}/*离开临界段*/LeaveCriticalSection(&m_cs_communication_sync);return OPER_SUCCESS;}在调⽤的exe程序那边,添加⽗类纯虚函数接⼝的头⽂件,然后引⼊获取单例接⼝的函数。
实验七虚函数及应用一、实验目的1.理解虚函数与运行时(动态)多态性之间的关系,掌握虚函数的定义及应用;2.理解纯虚函数与抽象类的概念,掌握抽象类的定义及应用;3.理解虚析构函数的概念及作用。
二、实验学时课内实验:2课时课外练习:2课时三本实验涉及的新知识㈠虚函数与动态多态性在C++中,如果将基类与派生类的同名成员函数定义为虚函数,就可以定义一个基类指针,当基类指针指向基类对象时访问基类的成员函数,当基类指针指向派生类对象时访问派生类的成员函数,实现在运行时根据基类指针所指向的对象动态调用成员函数,实现动态多态性。
换句话说,虚函数与派生类相结合,使C++能支持运行时(动态)多态性,实现在基类中定义派生类所拥有的通用“接口”,而在派生类中定义具体的实现方法,即“一个接口,多种方法”。
㈡虚函数的定义1.在基类中定义在定义函数的前面加上“virtual ”。
即:virtual 返回类型函数名(参数表){ …… }2.在派生类中定义函数的返回类型、函数名、参数的个数、参数类型及顺序必须与基类中的原型完全相同。
3.说明:⑴在派生类中定义虚函数时,可用“virtual”也可不用“virtual”(最好都使用)。
⑵虚函数在派生类中重新定义时,其原型必须与基类中相同。
⑶必须用基类指针访问虚函数才能实现运行时(动态)多态性;当用普通成员函数的调用方法(即用圆点运算符)调用虚函数时,为静态调用;⑷虚函数在自身类中必须声明为成员函数(不能为友元函数或静态成员函数),但在另一个类中可以声明为友元函数。
⑸虚函数可以公有继承多次,其虚函数的特性不变。
⑹构造函数不能定义为虚函数,但析构函数可以定义为虚函数。
⑺虚函数与重载函数的关系①普通函数重载是通过参数类型或参数的个数不同实现的;重载一个虚函数时,其函数原型(返回类型、参数个数、类型及顺序)完全相同。
②当重载的虚函数只有返回类型不同时,系统将给出错误信息;如果定义的虚函数只有函数名相同,而参数个数或类型不同时,则为普通函数重载。
c++ 基类纯虚函数C++是一种广泛使用的编程语言,同时也是面向对象编程语言。
在C++中,一个类可以从另一个类继承,这个类被称为基类,而继承的类被称为派生类。
基类中的纯虚函数是C++中非常重要的概念之一,它们在设计类的继承层次结构时非常有用。
纯虚函数是一种在基类中定义的虚函数,它没有任何实现代码,只是为了被继承类实现。
纯虚函数可以用一对`virtual`和`= 0`来声明,例如:```virtual void MyFunction() = 0;```这个声明告诉编译器MyFunction是一个虚函数,并且没有实现,只是一个接口,继承类必须对其进行实现。
纯虚函数在基类中起到了规范和约束作用,因为派生类必须实现这个函数才能实现自己的功能。
在许多情况下,基类中的纯虚函数是被设计为通用算法,由派生类提供特定的实现。
这种方法被称为“模板方法”模式。
在一个简单的图形库中,我们可以定义一个基类Shape,这个基类包含一个纯虚函数`Draw()`和派生类Rectangle和Circle。
Rectangle和Circle分别提供它们自己的特殊化实现,Draw()方法则会被调用以完成具体的实际操作。
在C++中,派生类中的实现方法可以通过覆盖和重载来完成。
覆盖是指派生类重新定义基类中的虚函数,以提供不同的实现方法。
重载是指派生类定义具有相同名称的函数,但它们具有不同的参数列表,这使得可以在相同的类中实现两个或更多的函数。
在实际开发中,如果我们定义了一个纯虚函数但没有提供实现,那么它将无法被实例化,因为它是一个抽象的函数。
通常情况下,如果我们忘记实现这个函数,可能会在编译时收到一个错误消息。
在设计一个类的继承时,纯虚函数是一种非常有用的技术。
它可以帮助我们将代码和数据聚集在一起,以便更好地组织和管理。
纯虚函数还可以使我们更迅速和简单地实现代码的重用和复用。
在C++中,基类中的纯虚函数是非常重要的。
它们可以帮助我们在类的继承层次结构中实现一些非常有用的功能,例如模板方法和多态。
C++中虚函数和纯虚函数的区别与总结⾸先:强调⼀个概念定义⼀个函数为虚函数,不代表函数为不被实现的函数。
定义他为虚函数是为了允许⽤基类的指针来调⽤⼦类的这个函数。
定义⼀个函数为纯虚函数,才代表函数没有被实现。
定义纯虚函数是为了实现⼀个接⼝,起到⼀个规范的作⽤,规范继承这个类的程序员必须实现这个函数。
1、简介假设我们有下⾯的类层次:class A{public:virtual void foo(){cout<<"A::foo() is called"<<endl;}};class B:public A{public:void foo(){cout<<"B::foo() is called"<<endl;}};int main(void){A *a = new B();a->foo(); // 在这⾥,a虽然是指向A的指针,但是被调⽤的函数(foo)却是B的!return 0;}这个例⼦是虚函数的⼀个典型应⽤,通过这个例⼦,也许你就对虚函数有了⼀些概念。
它虚就虚在所谓“推迟联编”或者“动态联编”上,⼀个类函数的调⽤并不是在编译时刻被确定的,⽽是在运⾏时刻被确定的。
由于编写代码的时候并不能确定被调⽤的是基类的函数还是哪个派⽣类的函数,所以被成为“虚”函数。
虚函数只能借助于指针或者引⽤来达到多态的效果。
C++纯虚函数⼀、定义 纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派⽣类都要定义⾃⼰的实现⽅法。
在基类中实现纯虚函数的⽅法是在函数原型后加“=0”virtual void funtion1()=0⼆、引⼊原因1. 为了⽅便使⽤多态特性,我们常常需要在基类中定义虚拟函数。
2. 在很多情况下,基类本⾝⽣成对象是不合情理的。
例如,动物作为⼀个基类可以派⽣出⽼虎、孔雀等⼦类,但动物本⾝⽣成对象明显不合常理。
#include<string.h>
#include<iostream>
using namespace std;
class XS{
public:
virtual void dispXM()=0;
virtual void dispXB()=0;
virtual void dispNL()=0;
};
class CZS:public XS
{
char xm[10];
char xb[5];
int nl;
public:
CZS(char *name1="周¨¹五?",char *sex1="男D",int age1=0) {strcpy(xm,name1);strcpy(xb,sex1);nl=age1;}
void dispXM();
void dispXB();
void dispNL();
};
void CZS::dispXM()
{
cout<<"the name is :"<<xm<<endl;
}
void CZS::dispXB()
{
cout<<"the sex is :"<<xb<<endl;
}
void CZS::dispNL()
{
cout<<"the age is :"<<nl<<endl;
}
class GZS:public XS{
char xm[10];
char xb[5];
int nl;
public:
GZS(char *name2="周¨¹LIU",char *sex2="男D",int age2=0) {strcpy(xm,name2);strcpy(xb,sex2);nl=age2;}
void dispXM();
void dispXB();
void dispNL();
};
void GZS::dispXM()
{
cout<<"the name is :"<<xm<<endl;
}
void GZS::dispXB()
{
cout<<"the sex is :"<<xb<<endl;
}
void GZS::dispNL()
{
cout<<"the age is :"<<nl<<endl;
}
class DZS:public XS{
char xm[10];
char xb[5];
int nl;
public:
DZS(char *name3="周¨¹7",char *sex3="女?",int age3=0)
{strcpy(xm,name3);strcpy(xb,sex3);nl=age3;}
void dispXM();
void dispXB();
void dispNL();
};
void DZS::dispXM()
{
cout<<"the name is :"<<xm<<endl;
}
void DZS::dispXB()
{
cout<<"the sex is :"<<xb<<endl;
}
void DZS::dispNL()
{
cout<<"the age is :"<<nl<<endl;
}
void main()
{
CZS student1("许¨ª约?","男D",16);
GZS student2("唐¬?哈t","女?",19);
DZS student3("楚t风¤?","男D",21);
cout<<"使º1用®?基¨´类¤¨¤的Ì?指?针?访¤?问¨º:êo"<<endl;
XS *p;
p=&student1;
p->dispXM();p->dispXB();p->dispNL();
p=&student2;
p->dispXM();p->dispXB();p->dispNL();
p=&student3;
p->dispXM();p->dispXB();p->dispNL();
cout<<"***********************"<<endl;
cout<<"使º1用®?基¨´类¤¨¤的Ì?引°y用®?访¤?问¨º:êo"<<endl;
XS &s1=student1;
s1.dispXM();
s1.dispXB();
s1.dispNL();
XS &s2=student2;
s2.dispXM();
s2.dispXB();
s2.dispNL();
XS &s3=student3;
s3.dispXM();
s3.dispXB();
s3.dispNL();
}。