带你掌握C++中三种类成员初始化方式
摘要:在C++11之后,声明时初始化->初始化列表->构造函数初始化。
本文分享自华为云社区《如何编写高效、优雅、可信代码系列(3)——类成员初始化的三种方式》,原文作者:我是一颗大西瓜。
首先,先得了解一下C++支持哪几种类成员初始化的方式,你常用的又是哪一种。
- 初始化方式一:初始化列表
class A
{
public:
int a; // 初始化列表
A(int a_):a(a_){}
};
- 初始化方式二:构造函数初始化
class A
{
public:
int a; // 初始化列表
A(int a_, bool b) { a = a_; }
};
- 初始化方式三:声明时初始化(也称就地初始化,c++11后支持)
class A
{
public:
int a = 1; // 声明时初始化
A() {}
};
在C++98中,支持了在类声明中使用等号“=”加初始值的方式,来初始化类中静态成员常量。这种声明方式我们也称之为“就地”声明。就地声明在代码编写时非常便利,不过C++98对类中就地声明的要求却非常高。如果静态成员不满足常量性,则不可以就地声明,而且即使常量的静态成员也只能是整型或者枚举型才能就地初始化。而非静态成员变量的初始化则必须在构造函数中进行。比如,如下代码在c++98中编译
class Init
{
public:
Init(): a(0) []
Init(int d): a(d) {}
private:
int a;
const static int b = 0; int c = 1; // member, cannot pass build
static int d = 0; // member, cannot pass build static const double e = 1.3; // not int or enum type, cannot pass build
stati const char* const f = "e"; // not int or enum type, cannot pass build
}
这非常不方便,所以在C++11中,标准允许非静态成员变量的初始化有多种形式。具体而言,除了初始化列表外,在C++11中,标准还允许使用等号= 或者 花括号{} 进行就地的非静态成员变量初始化。
struct init {
int a = 1;
double b {1.2};
};
大家知道,有几种情况下推荐优先使用列表初始化
- const成员变量只能用成员初始化列表来完成初始化,而不能在构造函数内赋值
- 初始化的数据成员是对象
- 需要初始化引用成员数据
具体的原因这里不细述,大家可以去看一下《C++ Primer》。
构造函数初始化的本质是赋值操作("="),这个方法存在两个问题,一个是比起初始化列表和就地初始化,此方式的效率偏低;第二个是可能存在错误隐患。
先说第一个,赋值过程中会产生临时对象,临时对象的构造析构会造成效率损耗,初始化列表的方式就避免了产生临时对象缩带来的问题。
第二个是,如果你没有重写或者禁止赋值构造函数,c++会悄悄的加上默认的赋值构造函数,这个时候也有可能带来问题。
从C++11之后,这三种初始化的方法都可以使用,并不会存在冲突,但是,他们之间是有优先级顺序的,这个优先级来源于他们在初始化的时间顺序,后面初始化的会把前面的覆盖掉,成员变量的初始化顺序是
声明时初始化->初始化列表->构造函数初始化
因此假如三种初始化方式同时存在的话,那么最后保留的成员变量值肯定是构造函数中初始化的值。
#include <iostream>
using namespace std;
class A
{
public:
int a = 1;
A(int a_) :a(2) { a = 3; }
}; int main()
{
A a;
cout << "a.a=" << a.a << endl;
return 0;
} // a.a=3
既然初始化方式这么多,那么什么时候适用哪种呢?
1. 声明时初始化的使用场景
- 一个优点是直观,你在声明的时候顺便给一个初始值,bravo,别人在看你代码的时候,点一下调到声明也能看到你赋予的初始值,不用再去看构造函数那里给的什么值
- 第二个优点更有用了,比如你要定义多个构造函数,每个构造函数都用列表初始化的方法初始化,多麻烦呀,请看下面的例子,妈妈看了再也不用担心我想用其他初始化方法了
class Group {
public:
Group() {}
Group(int a): data(a) {}
Group(Mem m): mem(m) {}
Group(int a, Mem m, string n): data(a), mem(m), name(n) {}
private:
int data = 1;
Mem mem{0};
string name{"Group"};
};
2. 列表初始化的使用场景
前面说过了三个场景,这里赘述一下
- const成员变量只能用成员初始化列表来完成初始化,而不能在构造函数内赋值
- 初始化的数据成员是对象
- 需要初始化引用成员数据
但是,需要注意列表初始化的顺序,不过IDE会提示你的
3. 构造函数初始化的使用场景
- 第一个就是拷贝和赋值构造函数里(不然怎么叫赋值构造函数呢)
- 第二个就是比较无聊的情况了,比如你想把几个成员函数都初始化成一个值,请看下面例子
class Group {
public:
Group() {data1 = data2 = data3 = 0;}
private:
int data1;
int data2;
int data3;
};
一言以蔽之,优先就地初始化和列表初始化。
带你掌握C++中三种类成员初始化方式的更多相关文章
- 深入浅出spring IOC中三种依赖注入方式
深入浅出spring IOC中三种依赖注入方式 spring的核心思想是IOC和AOP,IOC-控制反转,是一个重要的面向对象编程的法则来消减计算机程序的耦合问题,控制反转一般分为两种类型,依赖注入和 ...
- Java中final变量的初始化方式
原文转自:http://blog.csdn.net/zhangjk1993/article/details/24196847 public class FinalTest1 { //--------- ...
- C基础--结构体成员初始化方式
之前在linux内核代码中看到结构体成员成员初始化使用类似于.owner = THIS_MODULE, 不太见过,于是搜了个博客,分享下: 转自:http://www.cnblogs.com/Anke ...
- 【转】Spring 中三种Bean配置方式比较
今天被问到Spring中Bean的配置方式,很尴尬,只想到了基于XML的配置方式,其他的一时想不起来了,看来Spring的内容还没有完全梳理清楚,见到一篇不错的文章,就先转过来了. 以前Java框架基 ...
- Spring 中三种Bean配置方式比较
今天被问到Spring中Bean的配置方式,很尴尬,只想到了基于XML的配置方式,其他的一时想不起来了,看来Spring的内容还没有完全梳理清楚,见到一篇不错的文章,就先转过来了. 以前Java框架基 ...
- JS中三种字符串连接方式及其性能比较
工作中经常会碰到要把2个或多个字符串连接成一个字符串的问题,在JS中处理这类问题一般有三种方法,这里将它们一一列出顺便也对它们的性能做个具体的比较. 第一种方法 用连接符“+”把要连接的字符串连起来 ...
- 【SSH系列】深入浅出spring IOC中三种依赖注入方式
spring的核心思想是IOC和AOP,IOC-控制反转,是一个重要的面向对象编程的法则来消减计算机程序的耦合问题,控制反转一般分为两种类型,依赖注入和依赖查找,依赖什么?为什么需要依赖?注入什么?控 ...
- spring IOC中三种依赖注入方式
Spring的核心思想是IOC和AOP,IOC-控制反转,是一个重要的面向对象编程的法则,用来消减计算机程序之间的耦合问题,控制反转一般分为两种类型,依赖注入和依赖查找,依赖什么?为什么需要依赖?注入 ...
- c++中三种参数引用方式
传值调用 是默认的参数传递机制,实参会复制给形参,调用的语义是每次取得实参的副本并将该复本用作形参,即会有复本的开销,并且不改变实参的值. 适用于:传值调用用于不应该被函数改变的小型对象. 例子:vo ...
随机推荐
- 大华摄像头报警接口中图片加密,python调用c++方式实现解密
项目中,大华摄像头的报警信息,里面有图片地址,需要1天内取下来,保持留痕 可惜,图片下载后,加密了,大华提供了android,ios,c++例子,没有提供java解密例子 没办法,只好先用c++例子简 ...
- Spring Cloud Gateway之动态路由(数据库版)
1.实现动态路由的关键是RouteDefinitionRepository接口,该接口存在一个默认实现(InMemoryRouteDefinitionRepository) 通过名字我们应该也知道该实 ...
- jenkins邮件报警机制配置
1.下载email插件 Jenkins配置email前需要先安装email插件:Email Extension.Email Extension Template Plugin 2.系统配置 在Jenk ...
- mysql登录框注入绕过单引号匹配
0x00 原理 网站使用正则匹配对用户名一栏传到服务器的参数进行了匹配,如果匹配到了单引号则报错 0x01 简单例子 当我们输入admin'时,网站直接报错,很有可能就是用了正则,这样我们也不 ...
- 马哥Linux SysAdmin学习笔记(二)
Linux网络属性管理: 局域网:以太网,令牌环网 Ethernet:CSMA/CD 冲突域 广播域 MAC:media access control地址 48bit: 24bits 24bits ...
- Python菜鸟100例
题目地址 #-*- codeing = utf-8 -*- #@Time : 2021/3/18 21:17 #@Author : HUGBOY #@File : 1.py #@Software: P ...
- H5开发基础之像素、分辨率、DPI、PPI
H5开发基础之像素.分辨率.DPI.PPI html5 阅读约 4 分钟 2016-09-03于坝上草原 背景知识: 目前绝大部分显示器都是基于点阵的,通过一系列的小点排成一个大矩形,通过每个小 ...
- Windows 10 创建虚拟网卡
想把虚拟机桥接到我的电脑,但我连的是无线网电脑没查网线,所以就创建个虚拟网卡吧. 1.win + x 打开设备管理器 2.网络适配器 + 操作 + 添加过时硬件 3.下一步 4.选-->安 ...
- S11 Linux系统管理命令
11.1 lsof:查看进程打开的文件 11.2 uptime:显示系统的运行时间及负载 11.3 free:查看系统内存信息 11.4 iftop:动态显示网络接口流量信息 11.5 vmstat: ...
- python 交换变量值为何不需要中间变量
python 元组解包unpacking,同一语句中多重赋值 cpython 认为几种变量的交换是比较常见的,提供了专门的优化指令,像[-5,256]预先放到了整数池中一样,