虚函数:
概念:在类中声明为virtual的成员函数,称为虚函数,虚函数是c++中用于实现多态的机制。
核心理念就是:通过基类访问派生类定义的函数,是c++中多态行的一个重要体现,利用基类或基类对象的引用访问派生类中的成员函数。是c++中的一个重要体现,利用基类指针或者基类对象的引用访问派生类中的成员函数,这种情况下使用虚函数
语法:
class 类名 {访问权限: virtual 类型 函数名(形参列表) { 函数体 }};
纯虚函数:
概念:纯虚函数是在基类中只声明函数,没有实现,要求在派生类中定义的成员函数。
语法:
class 类名 {访问权限: virtual 类型 函数名(形参列表) = 0; //无函数体};
纯虚函数举例:
class A {
public:
virtual void Output() = 0;
};
class B : public A {
public:
virtual void Output(){
cout << "B::Output" << endl;
}
};
int main(){
A* p = new B;
p->Output();
}
类A是抽象类,不能创建对象
类B实现了基类的纯虚函数,就不再是抽象类,可以创建对象
抽象类:
1.有纯虚函数的类被称为抽象类或虚基类;
2.抽象类不能被实例化(不能定义对象);
3.从抽象类继承而来的派生类,可以不实现纯虚函数,如果不实现,派生类还是抽像类,不也可实例化
4.可以声明抽象类的指针和引用
单独解释一下:什么叫利用基类或基类对象的引用访问派生类中的成员函数
利用基类或基类对象的引用访问派生类中的成员函数是指通过基类类型的引用或基类对象来调用派生类中定义的成员函数。
在面向对象编程中,派生类继承了基类的成员(包括成员函数),因此可以通过派生类的对象直接访问这些成员函数。同时,由于派生类是基类的一种特殊类型,可以使用基类类型的引用或基类对象来引用派生类的对象。
通过基类或基类对象的引用访问派生类中的成员函数,可以实现一些多态的效果。多态是指相同的函数调用可以根据对象的实际类型执行不同的行为。当使用基类类型的引用或基类对象调用派生类中的成员函数时,会根据实际对象的类型来确定要调用的函数版本。
以下是一个示例代码,说明如何利用基类或基类对象的引用访问派生类中的成员函数:
#include <iostream>
using namespace std;
class Base {
public:
virtual void func() {
cout << "Base::func()" << endl;
}
};
class Derived : public Base {
public:
void func() override {
cout << "Derived::func()" << endl;
}
};
int main() {
Derived derivedObj;
Base& baseRef = derivedObj; // 使用基类类型的引用引用派生类对象
baseRef.func(); // 通过基类引用调用派生类中的成员函数
Base baseObj = derivedObj; // 使用基类对象存储派生类对象
baseObj.func(); // 通过基类对象调用派生类中的成员函数
return 0;
}
在上述示例中,Base
是基类,Derived
是派生类。通过基类类型的引用baseRef
和基类对象baseObj
分别引用和存储了派生类对象derivedObj
。然后,通过这些基类引用或对象调用func()
函数时,实际上会根据对象的实际类型来调用相应的函数版本
虚析构函数:
析构函数也可以定义为虚函数,如果基类的析构函数定义为虚析构函数,则派生类的析构函数就会自动成为虚析构函数
如果基类的指针指向派生类的对象,当用delete删除这个对象时,若析构函数不是虚析构函数,就只调用基类的析构函数,而不会调用派生类的析构函数
语法:
class 类名 {
访问权限:
virtual ~类名()
{函数体 }
};
虚函数表:
C++的虚函数是通过虚函数表来实现动态多态的。表里面存放了类中的虚函数地址信息。虚函数表指针放在对象的起始位置上。
#include <iostream>
using namespace std;
class A {
public:
int a;
int b;
virtual void test() {
cout << 1 << endl;
}
virtual void test1() {
cout << 2 << endl;
}
};
/*int main() {
A a;
A* ptr = &a;
ptr->test();
ptr->test1();
return 0;
}*/
int main()
{
A a;
cout << &a << endl;
cout << &a.a << endl;
cout << &a.b << endl;
return 0;
}
有的编译器有问题,可以设置更改
虚函数(Virtual Function)和纯虚函数(Pure Virtual Function)是C++中实现多态性的关键概念,它们有以下区别:
- 定义和实现:
-
- 虚函数是在基类中声明为虚函数的成员函数,它的定义和实现在基类中完成。虚函数通过在基类中使用关键字
virtual
来声明,派生类可以对虚函数进行重写(覆盖)。 - 纯虚函数是在基类中声明为纯虚函数的成员函数,它只有函数的声明而没有函数体。纯虚函数通过在基类中使用关键字
virtual
和= 0
来声明,派生类必须实现纯虚函数。
- 虚函数是在基类中声明为虚函数的成员函数,它的定义和实现在基类中完成。虚函数通过在基类中使用关键字
- 实现要求:
-
- 虚函数在基类中可以有默认的函数体,派生类可以选择是否重写虚函数。如果派生类没有重写虚函数,将沿用基类中的实现。
- 纯虚函数在基类中没有具体的实现,派生类必须实现纯虚函数,才能成为非抽象类。如果派生类没有实现纯虚函数,那么派生类也将成为抽象类。
- 对象实例化:
-
- 虚函数所在的类可以进行实例化,即可以创建对象。
- 含有纯虚函数的类无法进行实例化,即不能创建对象。只有通过派生类实现纯虚函数后,派生类才能实例化。
- 多态性:
-
- 虚函数实现了运行时多态性(Runtime Polymorphism),即在程序运行时根据对象的实际类型来确定要调用的函数版本。通过基类类型的指针或引用调用虚函数时,会根据对象的实际类型来调用相应的函数版本。
- 纯虚函数和抽象类实现了接口多态性(Interface Polymorphism),它们可以作为接口使用,通过基类指针或引用指向派生类对象,实现对派生类对象的统一操作。
总结:
- 虚函数是在基类中声明并实现的,派生类可以选择是否重写虚函数,实现运行时多态性。
- 纯虚函数是在基类中声明但没有具体实现的,派生类必须实现纯虚函数,实现接口多态性。含有纯虚函数的类无法实例化,只有通过派生类才能实例化。
- 虚函数和纯虚函数都是C++中实现多态性的重要机制。
-
----以下是个人的一些理解:
- 虚函数:
-
基类与派生类同名的函数前都有virtual关键字
通过派生类对象的引用或指针(转换为基类)来调用该函数
实际调用的是派生类的函数
- 纯虚函数
-
基类中的函数没有实现代码 只有声明
virtual 返回值 函数名(参数表)=0;那么该类就变为了抽象类
抽象类:不可以实例化对象
派生类中实现 若派生类中没有实现 则派生类也是抽象类
调用方式与虚函数一致
- 虚析构函数
-
防止派生类的析构函数不执行发生内存泄漏
若将基类的析构函数声明为虚析构函数 那么在delete基类的指针时 会先执行派生类的析构函数 再执行积累的析构函数
- 虚函数表:为了方便调用各个虚函数
-
若类中有虚函数 那么该类产生的对象的首地址存放的数据必然为虚函数的地址 则虚函数表实际是一个函数指针数组