c++ 中虚函数使用的非常广泛,关于虚函数有挺多用法的,各有各的不同
1、普通虚函数的定义
普通虚函数就是在函数前面加virtual 关键词 ,有虚函数的类中会存在一个虚函数指针在类内存布局中的开头,虚函数指针为4字节,指向虚函数表,虚函数表里面存储的是虚函数的函数指针地址
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
/// 虚函数类
class virtual_class {
public:
~virtual_class() = default;
virtual_class() = default;
virtual void fun() {
std::cout << "hello virtual fun" << std::endl;
};
};
int main()
{
virtual_class demo;
demo.fun();
}
2、虚函数的覆盖
在继承关系中虚函数的覆盖,子类覆盖父类的函数,覆盖函数名字相同、返回值相同、传参相同,如果父类存在虚函数,则继承情况下子类也会继承父类的虚函数表,存在覆盖情况,子类的函数会
替换掉虚函数表里面的函数指针指向
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
/// 虚函数类
class virtual_class {
public:
~virtual_class() = default;
virtual_class() = default;
virtual void fun() {
std::cout << "hello virtual_class fun" << std::endl;
};
};
///虚函数的覆盖
class virtual_class2 :public virtual_class {
public:
virtual_class2() = default;
~virtual_class2() = default;
void fun() {
std::cout << "hello virtual_class2 fun" << std::endl;
}
};
int main()
{
virtual_class demo;
demo.fun();
virtual_class2 demo2;
demo2.fun();
}
3、纯虚函数的使用
纯虚函数的定义,在虚函数后面使用 =0
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
/// 虚函数类
class virtual_class {
public:
virtual ~virtual_class() {
std::cout << " virtual_class 析构" << std::endl;
}
virtual_class() { }
virtual void fun() {
std::cout << "hello virtual_class fun" << std::endl;
};
/// 纯虚函数
virtual void setvalue(int va) = 0;
};
class virtual_class2 :public virtual_class {
public:
virtual_class2() {}
~virtual_class2() {
std::cout << " virtual_class2 析构" << std::endl;
}
void fun() {
std::cout << "hello virtual_class2 fun" << std::endl;
}
void setvalue(int va) {
value = va;
}
private:
int value;
};
4、多态中虚函数的析构
在多态继承的情况下,基类的析构函数要设置成虚函数,设置成虚函数的目的是在子类转成父类情况下,子类可以进行正常的析构,如果不设置成虚函数,子类最后会没有得到释放。析构函数的顺序从父类析构 ----》子类析构。
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
/// 虚函数类
class virtual_class {
public:
virtual ~virtual_class() {
std::cout << " virtual_class 析构" << std::endl;
}
virtual_class() { }
virtual void fun() {
std::cout << "hello virtual_class fun" << std::endl;
};
};
class virtual_class2 :public virtual_class {
public:
virtual_class2() {}
~virtual_class2() {
std::cout << " virtual_class2 析构" << std::endl;
}
void fun() {
std::cout << "hello virtual_class2 fun" << std::endl;
}
};
virtual_class* getVirtual()
{
return new virtual_class2;
}
int main()
{
virtual_class* demo4 = getVirtual();
delete demo4;
}
4、静态函数可以设置成虚函数吗?
原因如下: 静态函数不可以声明为虚函数,同时也不能被const 和 volatile关键字修饰,因为static 本身就不属于类,虚函数依靠vptr和vtable来处理。vptr是一个指针,在类的构造函数中创建生成,并且只能用this指针来访问它,静态成员函数没有this指针,所以无法访问vptr。
5、为什么构造函数不可以为虚函数?
尽管虚函数表vtable是在编译阶段就已经建立的,但指向虚函数表的指针vptr是在运行阶段实例化对象时才产生的。 如果类含有虚函数,编译器会在构造函数中添加代码来创建vptr。 问题来了,如果构造函数是虚的,那么它需要vptr来访问vtable,可这个时候vptr还没产生。 因此,构造函数不可以为虚函数。
我们之所以使用虚函数,是因为需要在信息不全的情况下进行多态运行。而构造函数是用来初始化实例的,实例的类型必须是明确的。 因此,构造函数没有必要被声明为虚函数。