1 初始化和赋值

  • 初始化:创建一个对象并赋予一个初值;
  • 赋值:通过赋值运算符(=),将“=”右侧值赋给“=”左侧对象;
int a=5;   //创建一个int对象a,初始值为5
a=12; //赋值

对于内置数据类型,初始化和赋值的区别不大;

对于自定义类型,初始化操作调用拷贝构造函数,赋值操作调用拷贝赋值运算符,下面以Person类为例;

//Person类
class Person {
public:
Person()
{
cout << "Person 默认构造调用" << endl;
}
Person(const char *name,int age)
{
cout << "Person有参构造调用" << endl;
this->m_Name = new char[strlen(name) + 1];
strcpy_s(this->m_Name, strlen(name) + 1, name);
this->m_Age = age;
}
Person(const Person&p)
{
cout << "Person 拷贝构造调用" << endl;
if (this->m_Name != NULL)
{
delete[]this->m_Name;
this->m_Name = NULL;
}
this->m_Name = new char[strlen(p.m_Name) + 1];
strcpy_s(this->m_Name,strlen(p.m_Name)+1, p.m_Name);
this->m_Age = p.m_Age;
}
Person&operator=(const Person &p)
{
cout << "Person拷贝赋值" << endl;
if (this->m_Name != NULL)
{
delete[]this->m_Name;
this->m_Name = NULL;
}
this->m_Name = new char[strlen(p.m_Name) + 1];
strcpy_s(this->m_Name, strlen(p.m_Name) + 1, p.m_Name);
this->m_Age = p.m_Age;
return *this;
}
void showInfo()
{
cout << this->m_Name << "今年" << this->m_Age << "岁!" << endl;
}
~Person()
{
cout << "Person析构调用" << endl;
if (m_Name != NULL)
{
delete[]m_Name;
m_Name = NULL;
}
}
char* m_Name;
int m_Age;
};
//测试函数
void test()
{
Person p("小明", 23);
p.showInfo();
cout<<endl;
Person p2(p);//也可写为Person p2=p,初始化
p2.showInfo();
cout<<endl;
Person p3;
p3 = p;//赋值
p3.showInfo();
cout<<endl;
}

运行结果

1.1 结论

通过程序运行结果可以知道,Person p2(p)语句调用类的拷贝构造函数,由于Person类中的m_Name是指向堆区空间的数据,所以我们必须提供自定义的拷贝构造函数,因为默认的拷贝构造函数只是简单的值拷贝;p3 = p语句调用类的拷贝赋值,同理编译器会提供一个默认的拷贝赋值运算符,也是简单的值拷贝,所以我们必须提供自定义的拷贝赋值运算符;

2 构造函数初始化列表

我们知道,构造函数是用来初始化类对象的数据成员,编写构造函数一般有两种方式,一种是通过在函数体里赋值实现,另一种是通过初始值列表,对于内置数据类型,这两种方式的相差无几,但是如果该类的数据成员有自定义的类型,那么就效率上讲,两者有些差别;

class MyClass1 {
public:
MyClass1()
{
cout << "myclass1 默认构造调用" << endl;
}
MyClass1(const MyClass1 &)
{
cout << "myclass1 默认拷贝构造调用" << endl;
}
MyClass1&operator=(const MyClass1 &)
{
cout << "myclass1 默认拷贝赋值调用" << endl;
return *this;
}
};
class MyClass2 {
public:
MyClass2(int a,MyClass1 &c)
{
this->m_A = a;
this->m_class = c;
}
//MyClass2(int a,MyClass1&c):m_A(a),m_class(c){}
int m_A;
MyClass1 m_class;
};
//测试函数
void test()
{
MyClass1 my1;
MyClass2 my2(3, my1);
}

运行结果

  1. 使用函数体内赋值

  1. 使用初始化列表

2.1 结论

通过运行结果可以知道对于自定义类型,通过初始化列表进行初始化,只需调用一次拷贝构造函数,而在构造函数中初始化,需要调用一次默认构造函数和一次赋值操作。

3 必须使用初始化列表的情况

如果类的数据成员是const,引用或者某种未提供默认构造函数的类类型,那么我们必须通过构造函数初始值列表为这些成员提供初值(c++prime第五版)

3.1 结论

建议养成使用构造函数初始值的习惯,这样能避免某些意想不到的编译错误

4 成员初始化顺序

构造函数初始值列表只说明用于初始化成员的值,并不限定初始化的具体顺序,成员的初始化顺序与它们在类定义中出现的顺序一致

class MyClass {
public:
MyClass(MyClass2 m2, MyClass3 m3, MyClass4 m4) :mc3(m3), mc4(m4), mc2(m2) {}//这里的顺序并不影响mc2,mc3,mc4的初始化顺序
//由下面出现的顺序决定,所以成员初始化顺序为:mc2->mc3->mc4
MyClass2 mc2;
MyClass3 mc3;
MyClass4 mc4;
};

5 参考资料

1.《c++prime 第五版》

2. https://blog.csdn.net/gxnu/article/details/1832462?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1

c++类初始化列表初探的更多相关文章

  1. 【c++】必须在类初始化列表中初始化的几种情况

    转自:http://www.cnblogs.com/kaituorensheng/p/3477630.html 1. 类成员为const类型 2. 类成员为引用类型 #include <iost ...

  2. C++类初始化列表

    转自:https://www.cnblogs.com/BlueTzar/articles/1223169.html 构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟 ...

  3. C++:四种必须使用初始化列表情况

    [c++]必须在类初始化列表中初始化的几种情况   1. 类成员为const类型   2. 类成员为引用类型   复制代码 #include <iostream> using namesp ...

  4. C++-什么时候需要在类的构造函数中使用初始化列表

    1,如果基类没有default构造函数,则意味着其不能自己初始化.如果其被派生,派生类的构造函数要负责调用基类的构造函数,并传递给它需要的参数.下例中Base 2,如果类成员没有默认构造函数.下例中E ...

  5. C++类构造函数初始化列表

    C++类构造函数初始化列表 构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式.例如: class CExample {public:     ...

  6. C++类的成员初始化列表的相关问题

    在以下四中情况下,要想让程序顺利编译,必须使用成员初始化列表(member initialization list): 1,初始化一个引用成员(reference member): 2,初始化一个常量 ...

  7. Effective C++学习笔记:初始化列表中成员列出的顺序和它们在类中声明的顺序相同

    类成员的默认初始化顺序是按照声明顺序进行, 如果使用初始化列表初始化成员变量, 则必须按照成员变量的声明顺序进行; 否则, 在变量之间交替赋值时, 会产生, 未初始化的变量去赋值其他变量; 同时GCC ...

  8. c++ 关于类构造函数的初始化列表

    除了性能问题之外,有些时场合初始化列表是不可或缺的,以下几种情况时必须使用初始化列表 常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面 引用类型,引用必须在定义的时候初始化,并且不能重 ...

  9. C++: 类成员初始化列表语法

      类的成员初始化列表的初始化的基本语法,类的构造函数还可以运用此语法为其变量初始化: class Class { private: int a; int b; char ch; public: Cl ...

随机推荐

  1. Java - Java开发中的安全编码问题

    目录 1 - 输入校验 1.1 SQL 注入防范 1.2 XSS防范 1.3 代码注入/命令执行防范 1.4 日志伪造防范 1.5 XML 外部实体攻击 1.6 XML 注入防范 1.7 URL 重定 ...

  2. js Object方法小结

    1. Object.defineProperty(obj,prop,{                 value:...,                 writable:boolean,//可写 ...

  3. 【swagger】C# 中 swagger 的使用及避坑

    @ 目录 1 安装 2 修改名称和版本号 3 显示说明 4 显示控制器注释及汉化 5 路由相同,查询参数不同的方法 6 忽略 Model 中的某些字段 7 传递 header 8 出错时的 HTTP ...

  4. Js闭包练习2020031801

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  5. js之for与forEach循环的区别

    回武汉打卡第四天,武汉加油,逆战必胜!今天咱们探讨一下for循环和forEach()循环的区别. 首先,for循环在最开始执行循环的时候,会建立一个循环变量i,之后每次循环都是操作这个变量,也就是说它 ...

  6. 1068 Find More Coins (30分)(dp)

    Eva loves to collect coins from all over the universe, including some other planets like Mars. One d ...

  7. 一篇blog带你了解java中的锁

    前言 最近在复习锁这一块,对java中的锁进行整理,本文介绍各种锁,希望给大家带来帮助. Java的锁 乐观锁 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人 ...

  8. Oracle 12C安装教程

    Oracle 12C安装教程 由 Alma 创建, 最后一次修改 2018-06-04 10:32:31 Oracle 12c,全称Oracle Database 12c,是Oracle 11g的升级 ...

  9. GIT本地安装及汉化

    GIT本地安装及汉化过程 1.下载地址: 链接:https://pan.baidu.com/s/1TMxxngZy4Y1De5eC1kSTMg 提取码:e593 2.下载完成之后如下图所示3个文件: ...

  10. MyBatis(八):高级结果映射

    本文是按照狂神说的教学视频学习的笔记,强力推荐,教学深入浅出一遍就懂!b站搜索狂神说或点击下面链接 https://space.bilibili.com/95256449?spm_id_from=33 ...