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

51单片机STC8G1K08驱动ws2812记录 使用51单片机控制17个2812灯,这里选择STC8芯片,最大频率可以达到35M,参考网上的各种文章案例,使用定时器做的时候实测做不到规格书要求的245-345ns,STC8G1K08不带PWM,所以只能使用nop来做,好在单片机在这里只有做编程灯的功能,省略测试过程,下面是程序,使用的是24MHz内部晶振 //设置一个灯珠 void SendOnePix(unsigned char *ptr) { unsigned char i,j; unsigned char temp; fo... 阅读详情

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

声音事件检测metric:PSDS 这项工作为多声道声音事件检测(SED)系统的性能评估定义了一个新的框架,它克服了传统的collar-based事件决定、事件F-cores和事件错误率的限制。拟议的框架引入了对事件检测的定义,该定义对标签的主观性更为稳健。它还采用了多声道接收器操作特性(ROC)曲线,以提供比F1分数更全面的系统性能洞察力,并建议将这些曲线简化为单一的多声道声音检测分数(PSDS),这允许系统独立于操作点(OPs)进行比较。所提出的方法还能更好地了解不同声音类别的数据偏差和分类稳定性。 阅读详情

相关推荐

学习stm32H7之路开始(STM32H7系列1) 前期准备,HAL库框架

2020.01.07 几个重要的参考网址 1.电子工程世界网 http://tags.eeworld.com.cn/tags/STM32H7 链接: link. 2.转:https://blog.youkuaiyun.com/simon223/article/list/2?t=1 链接: link. ———————————————— 版权声明:本文为优快云博主「Simon223」的原创文章,遵循 CC 4....

kengkengkeng963的博客 3410

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

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

王木木 6601

TortoiseSVN的安装与使用

TortoiseSVN的安装与应用1、安装1.1、下载TortoiseSVN    点击下载TortoiseSvn1.2、下载汉化包。上面的页面中,找到Chinese, simplified汉化包,点击32位或者64位的Setup,下载汉化包。1.3、安装TortoiseSVN。在选择安装路径页面时要记得勾选“command line client tools”,默认不是勾选的。这里不勾选的话在I...

qq_28566071的博客 4万+

C++虚函数详解

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

qq_42048450的博客 14万+

1.4 《SST通用技术规范》整体框架与核心条款解读

本小节以**GB/T《电力电子变压器通用技术要求》**(固态变压器SST核心通用规范)为核心依据,结合电力电子变压器技术特性与工程应用边界,系统解析规范的整体章节框架、层级逻辑与强制性/推荐性核心条款,明确规范与传统工频变压器标准的差异,为SST拓扑设计、性能验证、出厂检验与工程落地提供标准化依据。全文以标准原文、期刊文献数据与试验规范为支撑,无主观推演与感性表述。

技术工作者 1693

STM32开发笔记85: SX1268驱动程序设计(芯片唤醒)

单片机型号:STM32L053R8T6 本系列开发日志,将详述SX1268驱动程序的整个设计过程,本篇介绍芯片唤醒驱动程序。 一、RxDutyCycle模式 在讲述本篇内容之前,我们先来看一下SX1268的一种模式RxDutyCycle,译为中文为接收占空比模式。其可使用SetRxDutyCycle命令进入RxDutyCycle模式,我们来看一下该命令的详细解释。 该命令具有2个参数,...

snmplink的博客 4068

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

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

Mathias的博客 635

基于Python的MOOC课程评价爬取与分析系统设计与实现

本文详细介绍了如何使用Python最新技术栈构建一个高效的MOOC课程评价爬取与分析系统。系统采用Scrapy框架结合Selenium实现动态页面抓取,利用PyMySQL进行数据存储,并通过Pandas和Matplotlib实现数据可视化分析。文章从爬虫原理、技术选型、系统设计到代码实现进行全面讲解,为教育工作者改进教学质量提供数据支持。关键词:Python爬虫、MOOC评价分析、Scrapy框架、数据可视化、教学改进。

2201_76125261的博客 1103

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

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

weixin_39631899的博客 663

13《CAN总线五种错误类型,故障判定全解析》

CAN总线规定,发送节点在发送完EOF字段后,会留出一个ACK Slot(应答槽)。这个槽里,发送节点自己会输出隐性电平(逻辑1),然后“期待”至少有一个其他节点在这个槽里把它拉成显性电平(逻辑0)。如果这个槽结束时仍然是隐性电平,发送节点就判定:刚才那帧报文,没有任何一个节点成功接收——这就是应答错误。简单说,就是“我喊了一嗓子,却没人应声”。

2401_88858637的博客 265

Couldn‘t agree a key exchange algorithm(available:curve25519-sha256,curve25519-sha256@libssh.org解决方案

本文主要介绍了Couldn’t agree a key exchange algorithm(available:curve25519-sha256,curve25519-sha256@libssh.org解决方案,希望能对使用winscp的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案 2.1 方案一 2.2 方案二

weixin_43178406的博客 4万+

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

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

章飞 _906285288的博客 8241

零基础基于U-Net网络实战眼底图像血管提取

文章目录1 前言2 血管提取任务概述3 U-Net架构简介4 眼底图像血管分割代码5 结果评估可视化(ROC曲线)6 改进U-Net网络完成眼底图像血管提取任务思路 1 前言 本文基于U-Net架构完成了视网膜血管的提取任务,基于Keras框架更简单的实现分割,网络、工具类、训练和预测的代码一目了然

NJU phd 在读。 5203

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

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

Magnum的博客 1万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

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

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

布袋和尚 1260

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

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

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

TABE_的博客 7841

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

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++中static关键字
hellorichen
博客等级 码龄13年 199粉丝 104原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值