C++中构造函数、析构函数和虚函数

【DeepSeek+Office/WPS】智能办公新时代的全新利器 DeepSeek是一家专注于通用人工智能技术研发的中国科技公司,其核心产品DeepSeek-R1是一款开源的推理大模型,专注于复杂任务的高效处理,支持智能对话、文本生成、语义理解、计算推理、代码生成与补全等多种应用场景。作为国产、免费、开源且强大的AI平台,DeepSeek不仅致力于为终端用户提供高质量的智能服务,还为开发者提供了一整套完善的技术解决方案,帮助他们快速构建和部署自己的智能应用。 阅读详情

1.类

类的三个新特征:友元(friend)、可变成员和静态成员。

友元:允许一个类将对其非公有成员的访问权授予指定的函数或类。

2.new与delete

new时做了三件事:①分配内存空间。②调用构造函数。③返回对象指针。

delete时做了两件事:①调用析构函数。②释放内存空间。

3.构造函数

1)实参决定使用哪个构造函数。

2)构造函数自动执行。

3)先调用基类构造函数,再调用子类构造函数。

4)常见类型(无参、拷贝、重载)及调用过程。与等号运算符重载区分。

例1:

#include <iostream>
using namespace std;

class Complex
{        
private :
    double    m_real;
    double    m_imag;
    int id;
    static int counter;
public:
    //    无参数构造函数
    Complex(void)
    {
        m_real = 0.0;
        m_imag = 0.0;
        id=(++counter);
        cout<<"Complex(void):id="<<id<<endl;
    }
    //    一般构造函数(也称重载构造函数)
    Complex(double real, double imag)
    {
        m_real = real;
        m_imag = imag;        
        id=(++counter);
        cout<<"Complex(double,double):id="<<id<<endl;
    }
    //    复制构造函数(也称为拷贝构造函数)
    Complex(const Complex & c)
    {
        // 将对象c中的数据成员值复制过来
        m_real = c.m_real;
        m_imag = c.m_imag;
        id=(++counter);
        cout<<"Complex(const Complex&):id="<<id<<" from id="<<c.id<<endl;
    }            
    // 类型转换构造函数,根据一个指定的类型的对象创建一个本类的对象
    Complex(double r)
    {
        m_real = r;
        m_imag = 0.0;
        id=(++counter);
        cout<<"Complex(double):id="<<id<<endl;
    }
    ~Complex()
    {
        cout<<"~Complex():id="<<id<<endl;
    }
    // 等号运算符重载
    Complex &operator=( const Complex &rhs )
    {
        if ( this == &rhs ) {
            return *this;
        }
        this->m_real = rhs.m_real;
        this->m_imag = rhs.m_imag;
        cout<<"operator=(const Complex&):id="<<id<<" from id="<<rhs.id<<endl;
        return *this;
    }
};
int Complex::counter=0;
Complex test1(const Complex& c)
{
    return c;
}
Complex test2(const Complex c)
{
    return c;
}
Complex test3()
{
    static Complex c(1.0,5.0);
    return c;
}
Complex& test4()
{
    static Complex c(1.0,5.0);
    return c;
}
int main()
{
    Complex a,b;//各调用一次Complex(void)构造函数

    // 下面函数执行过程中各会调用几次构造函数,调用的是什么构造函数?
    Complex c=test1(a);//①test1()②拷贝构造函数
    Complex d=test2(a);//①拷贝②test2()③拷贝
	
	Complex h(c);//拷贝
	Complex i = h;   //拷贝,相当于Complex i(h);
	c=h;//等号运算符
    b = test3();//①一般②拷贝③等号
    b = test4();//①一般②等号

    Complex e=test2(1.2);//①类型转换②拷贝
    Complex f=test1(1.2);//①类型转换②拷贝
    Complex g=test1(Complex(1.2));//①类型转换②拷贝

}
注:

①等号:对象已初始化;拷贝:对象未初始化。

<pre name="code" class="cpp">Complex i = h;//调用拷贝;
i = h;//调用等号

 ② 

<span style="background-color: rgb(255, 255, 0);">Complex c = test1(a);//调用1次构造函数</span>
上式结果等价于

<span style="background-color: rgb(255, 255, 0);">Complex c1 = test1(a);//调用1次
Complex c = c1;//调用1次,总共2次,因为多了中间变量c1.</span>

4.析构函数

牢记析构函数的调用顺序(与构造函数的调用顺序相反)

什么时候调用析构函数?

1)对象生命周期结束,被销毁时;

2)delete指向对象的指针时,或delete指向对象的基类类型指针,而其基类虚构函数是虚函数时;

3)对象i是对象o的成员,o的析构函数被调用时,对象的析构函数也被调用。

例2:

class A
{
public:
	A()
	{
		cout<<"constructing A"<<endl;
	}
	~A()
	{
		cout<<"destructing A"<<endl;
	}
private:
	int a;
};

class B:public A
{
public:
	B()
	{
		cout<<"constructing B"<<endl;
	}
	~B()
	{
		cout<<"destructing B"<<endl;
	}
private:
	int b;
};

void main()
{
	B b;
}
输出结果:

说明:先调用父类构造方法,再调用子类构造方法。

上述代码说明了一件事:析构函数的调用顺序与构造函数的调用顺序相反。

例3:

main()方法改为:

void main()
{
	A *a = new B;
	delete a;
}
输出结果:


例4:

class A
{
public:
	A()
	{
		cout<<"constructing A"<<endl;
	}
	virtual ~A()
	{
		cout<<"destructing A"<<endl;
	}
private:
	int a;
};

class C
{
public:
 C()
 {
  cout<<"constructing C"<<endl;
 }
 ~C()
 {
  cout<<"destructing C"<<endl;
 }
 private:
  int c;
};

class B:public A
{
public:
	B()
	{
		cout<<"constructing B"<<endl;
	}
	~B()
	{
		cout<<"destructing B"<<endl;
	}
private:
	int b;
	C c;
};

void main()
{
	B b;
}
输出结果:


5.虚函数-virtual function

多态、虚函数表(内存中实例、最前面、地址表、父子类在内存中函数位置)、

5.1 定义

C++中虚函数的作用主要是实现了多态的机制。多态,简言之就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。

5.2 虚函数表

虚函数(virtual function)是通过一张虚函数表(virtual table)来实现的,简称V-Table。该表中,主要是一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其能真实地反映实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中。

C++中,编译器必须要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。

代码如下:

#include <iostream>
using namespace std;

class Base{
public:
	virtual void f(){cout<<"f()"<<endl;}
	virtual void g(){cout<<"g()"<<endl;}
	virtual void h(){cout<<"h()"<<endl;}
};

void main()
{
	Base b;
}
内存结构如下:

一般覆盖(无虚函数覆盖)

假设有如下所示的一个继承关系:

在这个继承关系中,子类没有重载任何父类的函数。那么,在派生类的实例中,其虚函数表如下所示:对应实例:Derive d;的虚函数表如下:

可看到下面几点:

1)虚函数按照其声明顺序存在于表中。

2)父类的虚函数在子类的虚函数前面。

一般继承(有虚函数覆盖)

虚函数如下所示:

从表中可看到以下几点

1)覆盖的f()函数被放到了虚表中原来父类虚函数的位置。

2)没有被覆盖的函数依旧。

多重继承(无虚函数覆盖)

从上面可看到以下几点:

1)每个父类都有自己的虚表

2)子类的成员函数被放到了第一个父类的表中

多重继承(有虚函数覆盖)



注:

一、::是运算符中等级最高的,表示作用域和所属关系,它分为三种:

1)global scope(全局作用域符),用法(::name)

2)class scope(类作用域符),用法(class::name)

3)namespace scope(命名空间作用域符),用法(namespace::name)

例5:类作用域

#include <iostream>
using namespace std;

class First{
public:
	int memi;
	double memd;
};
class Second{
public:
	int memi;
	double mend;
}

void main()
{
	First f;
	Second s = f;
}

提示错误:不存在用户定义的从"First"到"Second"的适当转换。每个类都定义了自己的新作用域和唯一的类型。两个不同的类具有两个不同的类作用域。即使两个类具有完全相同的成员列表,它们也是不同的类型。每个类的成员不同于任何其他类的成员。


结束语

C++这门语言是一门 Magic的语言,对于程序员来说,我们似乎永远摸不清楚 这门语言背着我们在干什么。需要熟悉这门语言,我们就必须了解C++里面的那些东西,需要去了解C++中那些危险的东西。不然,这是一种搬起石头砸自己的脚的编程语言。

参考:

http://www.cnblogs.com/xkfz007/archive/2012/05/11/2496447.html

http://blog.youkuaiyun.com/weizhee/article/details/562833

http://blog.youkuaiyun.com/wuchuanpingstone/article/details/6742465

基于步科(Kinco HMI 2.5)的组态软件使用 本篇介绍Kinco HMI 2.5的组态软件使用,图标如下 目录   一、新建工程并配置连接 1.1 根据工程选择PLC与HMI型号 1.2 配置PLC连接与选项 二、组态画面编辑 2.1 打开画面窗口 2.2 编辑画面 2.3 组态变量与PLC程序变量连接 三、组态程序下载到HMI 3.1 连接 3.2 编译 3.3 下载 一、新建工程并配置连接 1.1 根据工... 阅读详情

相关推荐

Qt QChart实战:从零打造一个实时温度监控仪表盘(附完整源码)

本文详细介绍了如何使用Qt QChart模块从零构建一个工业级实时温度监控仪表盘。通过实战案例,展示了波形图的绘制、坐标轴配置、数据流模拟等关键技术,并提供了完整的源码实现,帮助开发者快速掌握Qt在数据可视化领域的应用。

weixin_42537919的博客 243

C++:构造函数与虚构函数【详解】

C++作为一门面向对象的编程语言,在使用过程中,绝对会经常使用到类的构造函数及析构函数,本文主要总结了构造函数及析构函数的注意点。 1、构造函数 在对某类进行实例化时,一定会调用该类的构造函数,构造函数主要完成的是类成员变量的初始化(静态变量除外,它是在全局数据区进行初始化的)或者内存分配工作,构造函数无返回值,可根据参数个数及类型不同进行重载。 默认构造函数:默认构造函数时无参构造...

王木木 6601

Canoe Panel基础功能介绍

CANoe Panel 是 Vector CANoe 软件中用于设计图形化操作界面的功能模块。用户可以在面板上添加合适的控件,实时的改变信号或者变量的值

m0_56208280的博客 1951

C++虚函数详解

1.虚函数的使用? 1.1虚函数的定义 在实现c++多态时会用到虚函数。虚函数使用的其核心目的是通过基类访问派生类定义的函数。所谓虚函数就是在基类定义一个未实现的函数名,为了提高程序的可读性,建议后代中虚函数都加上virtual关键字。一般格式: class base { public: base(); virtual void test(); //定义的一个虚函数 private: char *basePStr; }; 上述代码在基类中定义了一个test的虚函数,所有可以在其子类重新定义父

qq_42048450的博客 14万+

Vue项目实战:海康WebControl插件从安装到预览功能全流程(附RSA加密避坑指南)

本文详细介绍了在Vue项目中集成海康威视WebControl插件的全流程,从环境准备、插件部署到核心功能实现。重点解析了使用JS_RequestInterface获取RSA公钥并进行加密参数初始化的关键步骤与常见避坑指南,帮助开发者高效完成监控视频预览功能的开发与调试。

linux6sysadmin的博客 1227

从数据手册到代码:一步步解读SC7A20寄存器配置与加速度值换算原理

本文详细解析了SC7A20三轴加速度传感器的寄存器配置与加速度值换算原理。从数据手册出发,逐步拆解关键寄存器设置,并推导原始ADC值到物理加速度的完整换算过程,帮助开发者深入理解传感器底层工作原理,提升嵌入式开发效率。

weixin_29179311的博客 368

C++中构造函数和析构函数与虚函数之间的关系要点

首先对构造函数、析构函数、虚函数的概念作出定义。 构造函数是类的同名成员函数,当创建类对象时它会自动执行,一般负责对类进行初始化、分配资源。 public: 类名(参数) { p = new int; } 注意: 构造函数的访问属性必须是public否则无法创建对象; 构造函数可以重载,可以有多个版本的构造函数; 调用带参数的构造函数:Test t(实参); 默认情况下编译器自动生成一个没有参数的,什么都不做的构造函数,如果一旦显式实现带参数的构造函数,则无参构造不生成,Text t调用无参构造时,如果没

Mathias的博客 635

YOLOv11改进入门篇 | 手把手讲解改进模块如何实现高效涨点,以SimAM注意力模块为例

本文记录的是基于SimAM注意力模块的YOLOv11目标检测方法研究。SimAM注意力模块通过优化能量函数来获得每个神经元的三维权重,而或增加计算复杂度。若是有轻量化需求的小伙伴,无参的注意力模块也许是一个不错的选择。

Limiiiing的博客 9039

c语言 头文件可以定义的函数吗_C++构造函数和析构函数可以是虚函数吗

先说结论:C++中,构造函数不可以是虚函数,而析构函数可以且常常是虚函数。虚函数的定义:类成员函数前面添加virtual关键字,则函数被称为虚函数。1、构造函数不可以是虚函数当类中声明虚函数时,编译器会在类中生成一个虚函数表,虚函数表是一个存储成员函数指针的数据结构。虚函数表是由编译器自动生成与维护的,virtual成员函数会被编译器放入虚函数表中,当存在虚函数时,每个对象都有一个指向虚函数的指针...

weixin_39631899的博客 663

【异常】飞书OpenClaw机器人 HTTP 401: Invalid Authentication 报错排查与解决方案

HTTP 401 是HTTP协议标准定义的未授权(Unauthorized)状态码,核心含义为请求方身份认证无效,服务端拒绝执行本次请求。飞书开放平台服务端对自建机器人的全链路鉴权校验失败。无论是机器人接收飞书事件推送的上行请求,还是机器人主动调用飞书开放平台API的下行请求,只要身份凭证无效、鉴权逻辑校验不通过,飞书服务端就会返回该报错,并最终透传到飞书客户端会话窗口中。

奶爸的编程之路,也就一周冷个三天 3762

【工业相机】【深度4】线扫描相机 - 选型实践

前言: 在工业相机的深度应用的前三节里面,针对工业相机的选型、参数、应用计算等做了一些说明。期中,在深度3里面,在说明工业相机在速度场景下的应用的时候,专门开了一节介绍线扫描相机行频速度的计算公式和镜头的选型的大致说明,感觉说的还是不够透彻,切应用举例也不充分,这里特别开一个章节,基于线扫描相机的特点对比面阵相机的特点进行比较详细的说明,尤其对线扫描相机的选型实践,尤其是线扫描相机的分辨率选择计算、行频选择计算进行了充分的说明和计算说明,希望能够给用到线扫描工业相机的同学给予一定的参考: 阐述: 在编

山云的专栏 2万+

C++学习:虚函数,纯虚函数(virtual),虚继承,虚析构函数

C++学习:虚函数,虚继承,纯虚函数(virtual)虚析构函数 虚函数 纯虚函数 虚析构函数 虚继承 简介 在java这种高级语言中,有abstract和interface这两个关键字.代表的是抽象类和接口,但是在C++这门语言中,并没有专属的关键字来表示抽象类或者接口,但是它却也有接口和抽象类这样的概念.所以在这里引入了vitural这个关键字,虚构的,虚有的意思. 因为C+

章飞 _906285288的博客 8241

深度解析机器人关节位置环控制:从理论到实践

本文系统阐述了机器人关节位置环控制的核心原理与实现方法。首先介绍了关节控制的基础框架,阐明位置环在闭环控制中的关键作用。随后深入解析PID控制算法原理,包括比例、积分、微分项的功能与参数整定原则。在软件实现部分,提供了模块化设计思路和Python伪代码示例,强调实时性保障和异常处理机制。文章还包含典型面试问题解答和应用案例,展示如何通过参数优化将定位精度提升20倍。最后指出未来发展趋势将聚焦算法自适应性和系统稳健性。全文兼顾理论深度与实践指导,为开发者提供从基础到进阶的完整技术路线图。

郑伟强dev的专栏 51

C++ 构造函数和析构函数可以是虚函数嘛?

简单总结就是:构造函数不可以是虚函数,而析构函数可以且常常是虚函数。 构造函数不能是虚函数 1. 从vptr角度解释 虚函数的调用是通过虚函数表来查找的,而虚函数表由类的实例化对象的vptr指针(vptr可以参考C++的虚函数表指针vptr)指向,该指针存放在对象的内部空间中,需要调用构造函数完成初始化。如果构造函数是虚函数,那么调用构造函数就需要去找vptr,但此时vptr还...

Magnum的博客 1万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

C/Cpp / C++ 构造函数和析构函数可以是虚函数吗

答案 构造函数不可以是虚函数,而析构函数可以且常常是虚函数。 原因 1、构造函数不可以是虚函数 当类中声明虚函数时,编译器会在类中生成一个虚函数表,虚函数表是一个存储成员函数指针的数据结构。 虚函数表是由编译器自动生成与维护的,virtual成员函数会被编译器放入虚函数表中,当存在虚函数时,每个对象都有一个指向虚函数的指针(vptr指针)。在实现多态的过程中,父类和派生类都有vptr指针。 vptr的初始化:当对象在创建时,由编译器对 vptr 指针进行初始化。在定义子类对象时,vptr 先指向

布袋和尚 1260

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C++ 构造函数和析构函数是否可以为虚函数?

简单总结就是:构造函数不可以是虚函数,而析构函数可以且常常是虚函数。 理由如下: 构造函数不能是虚函数 1.从vptr角度解释 虚函数的调用是通过虚函数表来查找的,而虚函数表由类的实例化对象的vptr指针(vptr可以参考C++的虚函数表指针vptr)指向,该指针存放在对象的内部空间中,需要调用构造函数完成初始化。如果构造函数是虚函数,那么调用构造函数就需要去找vptr,但此时vptr还没有初始化! 2.从多态角度解释 虚函数主要是实现多态,在运行时才可以明确调用对象,根据传入的对象类型来调用函数,例如通过

TABE_的博客 7841

C++中构造函数和析构函数能否是虚函数

作者:billy 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 前言 在C++的类中,当我们用到多态的时候会把基类中的某个函数定义为虚函数,然后在子类中重新实现这个函数。在此过程中我们引发了一个讨论,基类中的构造函数和析构函数是否也可以定义为虚函数呢?下面我们一起来分析一下。 构造函数 首先我们来看一下构造函数的定义: 类的构造函数是类的一种特殊的成员函数,它会在每...

billy的博客 1985

c++构造函数和析构函数中调用虚函数

# include < iostream >//program15.4.2.cpp构造函数和析构函数中调用虚函数 using namespace std; class A { public: virtual void hello() { cout << " A::hel1o" << endl; }; virtual void bye() { cout << "A::bye" << endl; }; }; class B :public A {

xuchaoxin1375的博客 885

C++ 构造函数和析构函数中调用虚函数的问题

C++构造函数和析构函数中调用虚函数效果与原因分析。

noevil的博客 1540

C++ 多态与虚函数、与构造函数和析构函数的联系

多态与虚函数 面向对象编程中,多态的含义是“一个接口,多种实现”。 多态分为静态多态和动态多态。静态多态是通过模板化和重载技术来实现,在编译的时候确定。动态多态通过虚函数和继承关系来实现,执行动态绑定,在运行的时候确定。 C++中运行时的多态是指根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。 C++多态性是通过虚函数来实现的,虚...

a834595603的博客 991

C++中最好不要在构造函数和析构函数中调用虚函数!!!

1.最好不要在基类和派生类的构造和析构函数中调用虚函数,不会出现多态性 实例如下: #include "iostream" using namespace std; class Base{ public: Base(){ cout << "Base::Base()\n"; ...

CurryCoder的个人博客 1108

子类重写父类虚函数_C++构造函数和析构函数可以是虚函数吗

先说结论:C++中,构造函数不可以是虚函数,而析构函数可以且常常是虚函数。虚函数的定义:类成员函数前面添加virtual关键字,则该函数被称为虚函数。1、构造函数不可以是虚函数当类中声明虚函数时,编译器会在类中生成一个虚函数表,虚函数表是一个存储成员函数指针的数据结构。虚函数表是由编译器自动生成与维护的,virtual成员函数会被编译器放入虚函数表中,当存在虚函数时,每个对象都有一个指向虚函数的指...

weixin_39973492的博客 916

C++ 在构造函数和析构函数中调用虚函数究竟会怎么样?

探究在构造函数和析构函数中调用虚函数究竟会导致什么样的结果,探究应有的预期,与可能的正确写法

icky的博客 7183

C++构造函数和析构函数调用虚函数时使用静态联编

转载自:https://www.cnblogs.com/bonelee/p/5826196.html #include <iostream> using namespace std; class A{ public: A() { show(); } virtual void show(){ cout<<"in A"<<endl; } virtual ~A(){ show(); .

weixin_44717047的博客 1365

C++基础| 多态 与 虚函数 大汇总:C++怎么实现多态 、虚函数和纯虚函数的区别 、虚函数是怎么实现的 、虚函数表是什么 、什么是构造函数和析构函数?构造函数、析构函数可以是虚函数吗

C++基础| 多态 与 虚函数 大汇总:C++怎么实现多态 、虚函数和纯虚函数的区别 、虚函数是怎么实现的 、虚函数表是什么 、什么是构造函数和析构函数?构造函数、析构函数可以是虚函数吗

2402_84438596的博客 1072

C++中为什么构造函数和析构函数不允许调用虚函数?

在C++中,构造函数不允许调用虚函数,这一规定是基于对象构造过程的安全性和一致性考虑。在对象未完全构造时调用虚函数,可能引发未定义行为,破坏程序的正确性。因此,我们应遵循这一规定,通过成员初始化列表、两阶段构造、工厂模式等替代方案,确保对象的正确初始化和多态行为的实现。

红军不怕远征难,万水千山只等闲 2593

C++:构造函数和析构函数能否为虚函数

C++:构造函数和析构函数能否为虚函数?简单回答是:构造函数不能为虚函数,而析构函数可以且常常是虚函数。(1) 构造函数不能为虚函数让我们来看看大牛C++之父 Bjarne Stroustrup 在《The C++ Programming Language》里是怎么说的:To construct an object, a constructor needs the exact ty

xhz1234的专栏 1万+
上一篇: C++指针详解
下一篇: C++中static关键字
hellorichen
博客等级 码龄13年 199粉丝 104原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值