c++--类型行为控制
1.c++的类
1.1.c++的类关键点
c++类型的关键点在于类存在继承。在此基础上,类存在构造,赋值,析构三类通用的关键行为。
类型提供了构造函数,赋值运算符,析构函数来让我们控制三类通用行为的具体表现。
为了清楚的说明类的构造,析构,赋值行为。我们采用一个具体的实例来验证这种行为。
// "test.h"
#include <iostream>class Norm1
{
public:Norm1() {printf("Norm1()_%c\n", m_i);}Norm1(char i):m_i(i) {printf("Norm1(int)_%c\n", m_i);}Norm1(const Norm1 &a):m_i(a.m_i){printf("Norm1(const Norm1&)_%c\n", m_i);}Norm1(Norm1&& a):m_i(a.m_i) {printf("Norm1(Norm1&&)_%c\n", m_i);}Norm1& operator=(const Norm1& a){m_i = a.m_i;printf("Norm1=(const Norm1&)_%c\n", m_i);return *this;}Norm1& operator=(Norm1&& a){m_i = a.m_i;printf("Norm1=(Norm1&&)_%c\n", m_i);return *this;}~Norm1(){printf("~Norm1()_%c\n", m_i);}
private:char m_i;
};class Norm2
{
public:Norm2() {printf("Norm2()_%c\n", m_i);}Norm2(char i):m_i(i) {printf("Norm2(int)_%c\n", m_i);}Norm2(const Norm2 &a):m_i(a.m_i){printf("Norm2(const Norm2&)_%c\n", m_i);}Norm2(Norm2&& a):m_i(a.m_i) {printf("Norm2(Norm2&&)_%c\n", m_i);}Norm2& operator=(const Norm2& a){m_i = a.m_i;printf("Norm2=(const Norm2&)_%c\n", m_i);return *this;}Norm2& operator=(Norm2&& a){m_i = a.m_i;printf("Norm2=(Norm2&&)_%c\n", m_i);return *this;}~Norm2(){printf("~Norm2()_%c\n", m_i);}
private:char m_i;
};class Base
{
public:Base():m_n2('b'),m_n1('b') {printf("Base()\n");}Base(char i):m_n2(i),m_n1(i) {printf("Base(int)\n");}Base(const Base &a):m_n2(a.m_n2), m_n1(a.m_n1){printf("Base(const Base&)\n");}Base(Base&& a):m_n2(a.m_n2),m_n1(a.m_n1) {printf("Base(Base&&)\n");}Base& operator=(const Base& a){m_n1 = a.m_n1;m_n2 = a.m_n2;printf("Base=(const Base&)\n");return *this;}Base& operator=(Base&& a){m_n1 = a.m_n1;m_n2 = a.m_n2;printf("Base=(Base&&)\n");return *this;}~Base(){printf("~Base()\n");}
private:Norm1 m_n1;Norm2 m_n2;
};class A : public Base
{
public:A():Base('b'),m_n1('a'),m_n2('a') {printf("A()\n");}A(char i): Base(i),m_n1(i),m_n2(i) {printf("A(int)\n");}A(const A &a):Base(a),m_n1(a.m_n1),m_n2(a.m_n2){printf("A(const A&)\n");}A(A&& a):Base(a),m_n1(a.m_n1),m_n2(a.m_n2) {printf("A(A&&)\n");}A& operator=(const A& a){Base::operator=(a);m_n1 = a.m_n1;m_n2 = a.m_n2;printf("A=(const A&)\n");return *this;}A& operator=(A&& a){Base::operator=(a);m_n1 = a.m_n1;m_n2 = a.m_n2;printf("A=(A&&)\n");return *this;}~A(){printf("~A()\n");}
private:Norm1 m_n1;Norm2 m_n2;
};
2.关于类的构造
2.1.构造函数执行顺序
#include "test.h"
int main()
{A a1;return 0;
}
上述代码编译运行后的输出:
这是因为对任意一个c++类型A其构造顺序为:
1.基类构造
2.成员变量按类内出现顺序构造
3.类自身的构造函数体
上述定义一个递归式的定义。
2.2.默认构造
(1).定义
不需要传递任何参数即可执行的构造函数称为默认构造。
class A1
{
public:A1(){}
};class A2
{
public:A2(int i = 0){}
};
上述A1()
算默认构造,A2(int i = 0)
也算默认构造。因为这些构造函数可以不用传递任何实参即可执行。如A1 a1;A2 a2;
将分别执行上述构造函数。
(2).合成版本
a.当一个c++类型定义中用户没有自定义任何构造函数时,编译器默认为其提供一个默认构造函数。
#include <iostream>
class A
{
public:A(const A&){printf("A(const A&)\n");}
};int main()
{A a;// err,因为已经存在自定义构造函数,无合成版本return 0;
}
b.默认构造函数可行的前提是:
1.基类支持默认构造
2.类的所有成员变量支持默认构造
#include <iostream>
class T
{
private:T(){}
};class A
{
public:private:T t;
};int main()
{A a;// err,因为类的成员t对A来说不支持默认构造return 0;
}
c.合成的默认构造的行为
1.基类默认构造
2.成员变量按类内出现顺序执行默认构造
3.类自身的构造函数体(合成下函数体为空)
上述定义是一个递归式的定义。
(3).显式请求合成版本
当用户自定义了构造函数,而我们依然希望编译器提供合成版本默认构造时可以用下述方式
#include <iostream>class A
{
public:A(int i){printf("A(int)\n");}A()=default;
};int main()
{A a;return 0;
}
3.拷贝构造
拷贝构造其实就是构造的一种类型。但是使用比较频繁,故单独拿出来再说一遍。
3.1.拷贝构造执行顺序
拷贝构造依然属于构造,所以遵循构造执行顺序。
#include "test.h"
int main()
{A a1;A a2(a1);return 0;
}
上述代码编译后,输出为:
其中蓝色部分对应A a2(a1);
这是因为对任意一个c++类型A其拷贝构造顺序为:
1.基类构造
2.成员变量按类内出现顺序构造
3.类自身的构造函数体
上述定义一个递归式的定义。
A的基础类型,A的成员变量的构造可能存在多个版本,具体采用那个版本呢:
1.匹配到的A的构造函数中构造列表指定了如何构造下,以构造列表中指定的为准。
2.匹配到的A的构造函数中构造列表未指定时,采用类型的默认构造。
3.2.默认构造
(1).定义
只需要传递类型自身一个实例即可执行的构造函数称为拷贝构造。
class A1
{
public:A1(const A1& a){}A1() = default;
};class A2
{
public:A2(const A2& a, int i = 0){}A2() = default;
};
上述A1(const A1& a)算默认构造,A2(const A2& a, int i = 0)也算默认构造。因为这些构造函数只需要传递类型自身一个实例即可执行。如A1 a1;A2 a11(a1);A2 a2;A2 a22(a2);
中A2 a11(a1)
和A2 a22(a2)
将分别执行上述拷贝构造。
因为拷贝构造也属于构造函数,所以定义了拷贝构造下,若希望提供合成版本默认构造函数,必须采用A1()=default
这样的方式显式请求。
(2).合成版本
a.对于拷贝构造,不同于默认构造。
默认构造是只要存在任何构造函数,就不会提供编译器合成的默认构造版本。
拷贝构造,允许存在其他构造函数,只要用户没有定义只接收自身实例即可执行的构造函数,编译器就会提供合成的拷贝构造。
b.合成版本行为表现
#include "test.h"
class B : public Base
{
public:
private:Norm1 m_n1;Norm2 m_n2;
};int main()
{B b1;B b2(b1);return 0;
}
上述输出中红色对于合成版本默认构造。蓝色对应合成版本拷贝构造。
合成拷贝构造下,构造顺序依然是:
1.基类构造
2.成员变量按类内出现顺序构造
3.类自身的构造函数体
上述定义一个递归式的定义。
不过此时,对基类,执行的是基类的拷贝构造。对成员变量,执行的也是其拷贝构造。类自身的拷贝构造函数体是空的。
c.默认构造函数可行的前提是:
1.基类支持拷贝构造
2.类的所有成员变量支持拷贝构造
#include <iostream>
class T
{
public:T(){}
private:T(T& t){}
};class A
{
public:private:T t;
};int main()
{A a;A a2(a);// err,因为A的成员t不支持拷贝构造。return 0;
}
(3).显式请求合成版本
拷贝构造严格来说没有显式请求的必要,因为只要用户没有通过只接收类型自身实例即可执行的构造函数,编译器总是会提供合成的拷贝构造。
4.关于类的赋值
4.1.赋值顺序
#include "test.h"
int main()
{A a1;A a2;a2 = a1;return 0;
}
上述紫红色的1,2,3对应a2=a1;
值得注意的是,赋值运算符不像构造函数,析构函数。
像构造函数无论如何总是会对基类执行构造,对类的成员执行构造。类的定义者只能通过构造初始化列表决定采用那个版本的基类构造,成员构造。但基类构造,成员构造作为两个执行阶段无论针对合成版本构造函数,还是用户自定义的构造函数总是存在的。
对赋值,如何用户自定义了赋值运算符,则,基类部分赋值,成员赋值全部依赖自定义函数体的实现。
上述紫红色包含1,2,3的原因是我们提供的自定义赋值运算符里面分别处理了基类赋值,成员赋值。
class A : public Base
{
public:A& operator=(const A& a){Base::operator=(a);m_n1 = a.m_n1;m_n2 = a.m_n2;printf("A=(const A&)\n");return *this;}private:Norm1 m_n1;Norm2 m_n2;
};
4.2.默认赋值运算符
(1).定义
赋值运算符属于运算符的范畴,其定义形式有相对较为严格的要求
class A1
{
public:A1& operator=(const A1& a){... }
};
作为赋值运算符:
1.返回值必须是类型自身的引用类型。
2.只能接收一个形参。
3.传递类型自身实例时,可以匹配到形参。所以下述,也是合法的自定义赋值运算符。
class A1
{
public:A1& operator=(A1 a){... }
};
(2).合成版本
a.何时合成
用户没有自定义赋值运算符时。
b.合成版本行为表现
#include "test.h"
class B : public A
{
private:Norm1 n1;
};int main()
{B b1;B b2 = b1;return 0;
}
上述紫红色1,2对应B的合成版本赋值运算符。
合成的赋值运算符:
1.通过基类赋值运算符完成基类赋值。
2.对每个成员执行其赋值运算符完成成员赋值。
c.合成版本可行的前提是:
1.基类支持赋值运算符
2.类的所有成员变量支持赋值运算符
#include <iostream>
class T
{
public:T(){}
private:T& operator=(T&){}
};class A
{
public:private:T t;
};int main()
{A a1;A a2;a2 = a1;// err,因为A的成员t不支持赋值运算符(t的赋值运算符对A不可见)return 0;
}
(3).显式请求合成版本
赋值运算符严格来说没有显式请求的必要,因为只要用户没有定义赋值运算符,编译器总是会提供合成的赋值运算符。
4.关于类的析构
4.1.析构顺序
#include "test.h"
int main()
{A a;return 0;
}
上述蓝色1,2,3对应A a;
中实例a的析构过程。
析构函数执行顺序为:
1.类自身的析构函数体
2.成员变量按类内出现顺序反向析构
3.基类析构
上述定义一个递归式的定义。
不像构造函数,析构函数没有初始值列表这样的东西。每个类型的析构函数也不存在多个版本。
4.2.合成版本
a.何时合成
只要用户没有自定义析构函数,编译器就会合成析构函数。
b.合成版本行为表现
1.类自身的析构函数体。合成版本函数体为空。
2.成员变量按类内出现顺序反向析构
3.基类析构
上述定义一个递归式的定义。
c.合成版本可行前提
1.类的基类支持析构
2.类的成员支持析构
4.3.显式请求合成版本
析构函数严格来说没有显式请求的必要,因为只要用户没有定义析构函数,编译器总是会提供合成的析构函数。
相关文章:
c++--类型行为控制
1.c的类 1.1.c的类关键点 c类型的关键点在于类存在继承。在此基础上,类存在构造,赋值,析构三类通用的关键行为。 类型提供了构造函数,赋值运算符,析构函数来让我们控制三类通用行为的具体表现。 为了清楚的说明类的构…...
笔记64:Bahdanau 注意力
本地笔记地址:D:\work_file\(4)DeepLearning_Learning\03_个人笔记\3.循环神经网络\第10章:动手学深度学习~注意力机制 a a a a a a a a a a a...
面试官问:如何手动触发垃圾回收?幸好昨天复习到了
在Java中,手动触发垃圾回收可以使用 System.gc() 方法。但需要注意,调用 System.gc() 并不能确保立即执行垃圾回收,因为具体的垃圾回收行为是由Java虚拟机决定的,而不受程序员直接控制。 public class GarbageCollectionExample …...
操作系统的运行机制+中断和异常
一、CPU状态 在CPU设计和生产的时候就划分了特权指令和非特叔指令,因此CPU执行一条指令前就能断出其类型 CPU有两种状态,“内核态”和“用户态” 处于内核态时,说明此时正在运行的是内核程序,此时可以执行特权指令。 处于用户态…...
Python实战:批量加密Excel文件指南
更多Python学习内容:ipengtao.com 大家好,我是彭涛,今天为大家分享 Python实战:批量加密Excel文件指南,全文3800字,阅读大约10分钟。 在日常工作中,保护敏感数据是至关重要的。本文将引导你通过…...
二叉树链式结构的实现和二叉树的遍历以及判断完全二叉树
二叉树的实现 定义结构体 我们首先定义一个结构来存放二叉树的节点 结构体里分别存放左子节点和右子节点以及节点存放的数据 typedef int BTDataType; typedef struct BinaryTreeNode {BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right; }BTNode;…...
vue中的动画组件使用及如何在vue中使用animate.css
“< Transition >” 是一个内置组件,这意味着它在任意别的组件中都可以被使用,无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发: 由 v-if 所触发的切换由 v-show 所触…...
qt 5.15.2 网络文件下载功能
qt 5.15.2 网络文件下载功能 #include <QCoreApplication>#include <iostream> #include <QFile> #include <QTextStream> // #include <QtCore> #include <QtNetwork> #include <QNetworkAccessManager> #include <QNetworkRep…...
Wifi adb 操作步骤
1.连接usb 到主机 手机开起热点,电脑和车机连接手机,或者电脑开热点,车机连接电脑,车机和电脑连接同一个网络 因为需要先使用usb,后面切换到wifi usb 2.查看车机ip地址,和电脑ip地址 电脑win键r 输入cmd…...
湿货 - 231206 - 关于如何构造输入输出数据并读写至文件中
TAG - 造数据、读写文件 造数据、读写文件 造数据、读写文件//*.in // #include<bits/stdc.h> using namespace std;/* *********** *********** 全局 ********** *********** */ string Pre_File_Name; ofstream IN_cout; int idx;void Modify_ABS_Path( string& …...
EasyMicrobiome-易扩增子、易宏基因组等分析流程依赖常用软件、脚本文件和数据库注释文件
啥也不说了,这个好用,给大家推荐:YongxinLiu/EasyMicrobiome (github.com) 大家先看看引用文献吧,很有用:https://doi.org/10.1002/imt2.83 还有这个,后面马上介绍:YongxinLiu/EasyAmplicon: E…...
【Python百宝箱】漫游Python数据可视化宇宙:pyspark、dash、streamlit、matplotlib、seaborn全景式导览
Python数据可视化大比拼:从大数据处理到交互式Web应用 前言 在当今数字时代,数据可视化是解释和传达信息的不可或缺的工具之一。本文将深入探讨Python中流行的数据可视化库,从大数据处理到交互式Web应用,为读者提供全面的了解和…...
企业数字档案馆室建设指南
数字化时代,企业数字化转型已经成为当下各行业发展的必然趋势。企业数字化转型不仅仅是IT系统的升级,也包括企业内部各种文件、档案、合同等信息的数字化管理。因此,建设数字档案馆室也变得尤为重要。本篇文章将为您介绍企业数字档案馆室建设…...
JavaScript中处理时间差
ES6版本 function countdown(endTime, includeSeconds true) {// 获取当前时间let now new Date();// 将传入的结束时间字符串转换为日期对象let endDateTime new Date(endTime);// 检查传入的时间字符串是否只包含日期(不包含时分秒)if (endTime.tr…...
Multidimensional Scaling(MDS多维缩放)算法及其应用
在这篇博客中,我将与大家分享在流形分析领域的一个非常重要的方法,即多维缩放MDS。整体来说,该方法提供了一种将内蕴距离映射到显性欧氏空间的计算,为非刚性形状分析提供了一种解决方案。当初就是因为读了Bronstein的相关工作【1】…...
单片机_RTOS_架构
一. RTOS的概念 // 经典单片机程序 void main() {while (1){喂一口饭();回一个信息();} } ------------------------------------------------------ // RTOS程序 喂饭() {while (1){喂一口饭();} }回信息() {while (1){回一个信息();} }void main() {create_task(喂饭);cr…...
Golang rsa 验证
一下代码用于rsa 签名的验签, 签名可以用其他语言产生。也可以用golang生成。 package mainimport ("crypto""crypto/rsa""crypto/sha256""crypto/x509""encoding/pem""errors""fmt" )fun…...
网络安全威胁——跨站脚本攻击
跨站脚本攻击 1. 定义2. 跨站脚本攻击如何工作3. 跨站脚本攻击类型4. 如何防止跨站脚本攻击 1. 定义 跨站脚本攻击(Cross-site Scripting,通常称为XSS),是一种典型的Web程序漏洞利用攻击,在线论坛、博客、留言板等共享…...
Java利用UDP实现简单的双人聊天
一、创建新项目 首先创建一个新的项目,并命名。 二、实现代码 import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.net.*; import java.io.IOException; import java.lang.String; public class liaotian extends JFrame{ pri…...
HBase整合Phoenix
文章目录 一、简介1、Phoenix定义2、Phoenix架构 二、安装Phoenix1、安装 三、Phoenix操作1、Phoenix 数据映射2、Phoenix Shell操作3、Phoenix JDBC操作3.1 胖客户端3.2 瘦客户端 四、Phoenix二级索引1、为什么需要二级索引2、全局索引(global index)3、…...
C# 委托/事件/lambda
概念 委托 定义委托编译器会自动生成一个类派生自System.MulticastDelegate 这个类包含4个方法:一个构造器、Invoke、BeginInvoke、EndInvoke。 调用委托的时候实际上执行的是 Invoke方法。 MulticastDelegate类有三个重要字段: _targetÿ…...
13款趣味性不错(炫酷)的前端动画特效及源码(预览获取)分享(附源码)
文字激光打印特效 基于canvas实现的动画特效,你既可以设置初始的打印文字也可以在下方输入文字可实现激光字体打印,精简易用。 预览获取 核心代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&q…...
C# 友元程序集
1.友元程序集 使用友元程序集可以将internal成员提供给其他的友元程序集访问。 程序集FriendTest1.dll [assembly:InternalsVisibleTo("FriendTest2")] namespace FriendTest1 {internal class Friend{string name;public string Name > name;public Friend(str…...
CRM系统的数据分析和报表功能对企业重要吗?
竞争日益激烈,企业需要更加高效地管理客户关系,以获取更多的商机。为此,许多企业选择使用CRM系统。在CRM中,数据分析功能扮演着重要的角色。下面就来详细说说,CRM系统数据分析与报表功能对企业来说重要吗? …...
【单体架构事务失效解决方式之___代理对象加锁】
单体架构__用户限买 一个id一单的多线程事务失效问题解决 背景介绍:有一种情况,我们在使用Synchronized的时候出现失效情况。 经过排查,是因为使用了this.当前对象,他现在使用的是目标对象加锁失效,使用代理对象加锁就…...
面试被问到 HTTP和HTTPS的区别有哪些?你该如何回答~
HTTP和HTTPS的区别有哪些,主要从以下几个方面来说: 1.安全性 HTTP和HTTPS是两种不同的协议,它们之间最主要的区别在于安全性。HTTP协议以明文方式发送内容,不提供任何方式的数据加密,容易被攻击者截取信息。 HTTPS则在…...
点评项目——短信登陆模块
2023.12.6 短信登陆如果基于session来实现,会存在session共享问题:多台Tomcat不能共享session存储空间,这会导致当请求切换到不同服务器时出现数据丢失的问题。 早期的解决办法是让session提供一个数据拷贝的功能,即让各个Tomcat的…...
2023亚太地区五岳杯量子计算挑战赛
计算电源网 (CPN)布局优化 1. 介绍 计算能力网络 (CPN)是一种基于业务需求分配和调度计算资源的新型信息基础设施,计算资源通常由终端用户、边缘服务器和云服务器组成。该网络旨在满足各种计算任务的需求。根据计算需求的空间分…...
Python 模块的使用方法
Python 模块是一种组织和封装代码的方式,允许你将相关的功能和变量放在一个单独的文件中,以便在其他程序中重复使用。在Python中,模块是一种可执行的Python脚本,其文件扩展名为 .py。这里,我将详细讲解Python模块的使用…...
【知识】稀疏矩阵是否比密集矩阵更高效?
转载请注明出处:小锋学长生活大爆炸[xfxuezhang.cn] 问题提出 有些地方说,稀疏图比密集图的计算效率更高,真的吗? 原因猜想 这里的效率高,应该是有前提的:当使用稀疏矩阵的存储格式(如CSR)时,计…...
cms网站开发/推广app接单网
给你一个日志数组 logs。每条日志都是以空格分隔的字串,其第一个字为字母与数字混合的 标识符 。 有两种不同类型的日志: 字母日志:除标识符之外,所有字均由小写字母组成数字日志:除标识符之外,所有字均由…...
深圳市住建局和建设局官网/seo排名怎么做
参考链接: class.__mro__ 参考链接: class.mro() 参考链接: class.__subclasses__() 实验代码展示: # class Person(): # class Person(object): # class Person: class Person: # class Person(object): # class Person: # class Person(): 这三种写法都是可以的定义基类Pe…...
外贸网站运营怎么做/推广营销大的公司
场景 用的数据库是mysql5.6,下面简单的介绍下场景 课程表: 数据100条 学生表: 数据70000条 学生成绩表SC: 数据70w条 查询目的: 查找语文考100分的考生 查询语句: 执行时间:30248.271s 为…...
属于b2b的网站/app有哪些推广方式
为了更好的对客户端权限进行管理和控制,我们只赋予终端用户Domain User组的权限。但有些需要Local Administrator权限的软件就无法安装和运行。我目前能想到的办法是: 1、所有软件都安装在固定的Program Files目录,并通组策略赋予Program Fil…...
做 在线观看免费网站有哪些/注册城乡规划师教材
文|曾响铃 来源|科技向令说(xiangling0815) 最近,知名新经济行业数据挖掘和分析机构iiMedia Research(艾媒咨询)权威发布《2018Q1中国手机音乐客户端季度监测报告》,该报告显示,一季度我国移动端在线音乐用户总规模…...
怎么攻击织梦网站/网络营销与直播电商
给定一个二叉树,找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例: 给定二叉树 [3,9,20,null,null,15,7],3/ \9 20/ \15 7 返回它的最大深度 3 。 java代码的…...