虚函数之二

简介: 一. 设置虚函数需要考虑五个方面1. 只有类的成员函数才能声明为虚函数2. 类的静态成员函数不能为虚函数,因为调用静态成员函数不需要实例只需要用类名即可。


一. 设置虚函数需要考虑五个方面

1. 只有类的成员函数才能声明为虚函数


2. 类的静态成员函数不能为虚函数,因为调用静态成员函数不需要实例只需要用类名即可。而调用一个虚函数需要类的实例化对象,因为需要从实例化对象中的指向虚函数表的指针得到虚函数的地址,所以静态成员函数是不能为虚函数的


3. 内联函数不能为虚函数。

    因为内联函数是在编译的时候决定要不要内联的,内联函数原理是在程序中有用到内联函数的地方直接把程序代码插入,这样省去了函数调用的时间开销,提高了效率。 

    虚函数是在运行的时候动态的决定要调用哪个函数,因此内联函数是不能为虚函数的。


4. 构造函数不能为虚函数

    构造函数是在构造一个对象之前调用的,我们知道调用虚函数是需要类的实例化对象中指向虚函数表的指针的,但是构造函数在此时是没有构造出对象的,因此两者之间矛盾,所以构造函数是不能为虚函数的。

    虽然构造函数不能为虚函数,但是构造函数可以调用虚函数,例子如下

#include<iostream>
#include<algorithm>
using namespace std;

//类A
class A{
public:
	A(){
	     Print();
	}
	//类A的虚函数
	virtual void Print(void){
	     cout<<"class A"<<endl;
	}
private:
};

//类B继承类A
class B:public A{
public:
	B(){}
	//类B中重写A的虚函数
	virtual void Print(void){
	     cout<<"class B"<<endl;
	}
private:
};

int main(){
	//test
	A *a = new B();
	a->Print();
	getchar();
	return 0;
}
/*
程序输出:
class A
class B
解释如下:
1. main函数中基类指针a生成了一个子类对象,这个时候会先调用基类的构造函数
   再调用子类的构造函数,因为在基类A构造函数中调用了虚函数所以输出了class A
2. 基类指针调用Print函数,这个时候调用的是子类的函数,输出class B
*/

5.  析构函数可以为虚函数,一般情况下基类的析构函数声明为虚函数

     因为当基类指针指向子类对象的时候,如果这个时候delete基类指针,如果基类的析构函数是虚函数那么会先去执行子类的虚构函数再执行基类的析构函数;如果基类的析构函数不是虚函数则只会执行基类的析构函数,这样可能造成子类对象销毁不完全,可能有内存泄漏问题

     例子如下

【基类析构函数是虚函数】

#include<iostream>
#include<algorithm>
using namespace std;

//类A
class A{
public:
	virtual ~A(void){
	    cout<<"~A()"<<endl;
	}
private:
};

//类B继承类A
class B:public A{
public:
	~B(void){
	     cout<<"~B()"<<endl;
	}
private:
};

int main(){
	//test
	A *a = new B();
	delete a;
	a = NULL;
	getchar();
	return 0;
}
/*
输出:
~B()
~A()
解释如下:
1. 基类A的析构函数为虚函数
2. main函数中基类指针生成了一个子类B的对象,然后delete基类指针a
   由于基类析构函数是虚函数,因此会先执行子类B的析构函数再执行基类
   A的析构函数
*/

【基类析构函数不是虚函数】

#include<iostream>
#include<algorithm>
using namespace std;

//类A
class A{
public:
	~A(void){
	    cout<<"~A()"<<endl;
	}
private:
};

//类B继承类A
class B:public A{
public:
	~B(void){
	     cout<<"~B()"<<endl;
	}
private:
};

int main(){
	//test
	A *a = new B();
	delete a;
	a = NULL;
	getchar();
	return 0;
}
/*
输出:
~A()
解释如下:
1. 基类A的析构函数不是虚函数
2. main函数中基类指针生成了一个子类B的对象,然后delete基类指针a
   由于基类析构函数不是虚函数,因此只会执行基类A的析构函数
*/


目录
相关文章
|
6月前
|
存储 C++ 容器
第十四章:C++虚函数、继承和多态详解
第十四章:C++虚函数、继承和多态详解
58 0
|
5月前
|
编译器 C++ 开发者
通俗讲解 初学者一文看懂!虚函数、函数重载、重写的区别
函数重载允许在同一作用域内定义同名但参数列表不同的函数,提高代码灵活性和可读性,避免命名冲突。通过参数类型自动选择合适版本,如C++中的`print()`可处理整数、浮点数和字符串。虚函数实现运行时多态,基类指针调用时调用实际对象的版本。抽象类至少有一个纯虚函数,不能实例化,用于定义接口规范。抽象类和纯虚函数是构建多态和继承体系的基础,提供接口标准,减少代码冗余,增强代码清晰性和可维护性。
|
5月前
|
编译器 C++
C++进阶之路:何为默认构造函数与析构函数(类与对象_中篇)
C++进阶之路:何为默认构造函数与析构函数(类与对象_中篇)
34 0
|
6月前
|
数据安全/隐私保护 C++
C++中的虚函数、纯虚函数与函数重写的技术性探讨
C++中的虚函数、纯虚函数与函数重写的技术性探讨
91 0
|
6月前
|
存储 算法 编译器
【C++入门到精通】C++入门 —— 多态(抽象类和虚函数的魅力)
多态是面向对象编程中的一个重要概念,指的是同一个消息被不同类型的对象接收时产生不同的行为。通俗来说,**就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态**。
71 0
|
6月前
|
存储 编译器 C语言
C++初阶类与对象(一):学习类与对象、访问限定符、封装、this指针
C++初阶类与对象(一):学习类与对象、访问限定符、封装、this指针
69 0
|
编译器 C++
《C++避坑神器·六》多继承下问题处理(同名变量,信号槽,多态内存释放)
《C++避坑神器·六》多继承下问题处理(同名变量,信号槽,多态内存释放)
54 0
|
编译器 C语言 C++
C++ 虚函数简介
C++ 虚函数简介
|
Linux C++
【C++】多态(万字详解) —— 条件 | 虚函数重写 | 抽象类 | 多态的原理(下)
【C++】多态(万字详解) —— 条件 | 虚函数重写 | 抽象类 | 多态的原理(下)
144 0
【C++】多态(万字详解) —— 条件 | 虚函数重写 | 抽象类 | 多态的原理(下)
|
编译器 C++
【C++】多态(万字详解) —— 条件 | 虚函数重写 | 抽象类 | 多态的原理(上)
【C++】多态(万字详解) —— 条件 | 虚函数重写 | 抽象类 | 多态的原理(上)
168 0
【C++】多态(万字详解) —— 条件 | 虚函数重写 | 抽象类 | 多态的原理(上)