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. Matplotlib 精简实例入门

    Matplotlob 简明实例入门 通过几个实例,快速了解matplotlib.pyplot 中最为常见的折线图,散点图,柱状图,直方图,饼图的用法 如果您需要更为详细的内容,请参考官方文档: htt ...

  2. Django 视图笔记

    视图 概述 作用:视图接受web请求,并响应 本质:python中的一个函数 响应: 网页;重定向:错误视图(404.500) json数据 url配置 配置流程 1:指定根基url配置文件 sett ...

  3. leetcode 945. 使数组唯一的最小增量

    题目 给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1. 返回使 A 中的每个值都是唯一的最少操作次数. 示例 1: 输入:[1,2,2] 输出:1 解释:经过一次 mov ...

  4. Prism 源码解读3-Modules加载

    介绍 在软件开发过程中,总想组件式的开发方式,各个组件之间最好互不影响,独立测试.Prism的Modules很好的满足了这一点. 这个架构图很好了讲解了Prism的Modules的概念 Prism支持 ...

  5. JavaScript 趣味题。

    第一题: const Greeters = [] for (var i = 0 ; i < 10 ; i++) { Greeters.push(function () { return cons ...

  6. Mysql 随笔记录

    Soundex 声音相似的 select * from demos where Soundex('title') = Soundex('标示'); Concat 拼接语句 select concat( ...

  7. Python面向对象之异常处理

    1:什么是异常 异常就是在我们的程序在运行过程中由于某种错误而引发Python抛出的错误: 异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序 ...

  8. 运输问题中产销不平衡问题(表上作业法和LINGO方法)

    对于产销不平衡问题有两种情况: 供大于求(产大于销)→增加虚拟销地 供不应求(产小于销)→增加虚拟产地 例如以下例题: 这个题中,总产量为55,总销量为60,故而我们知道这个问题属于供不应求. 1.这 ...

  9. 【Java技术系列】爱情36技之记忆永存

    1.  关注“一猿小讲”的伙伴们都清楚,Java 那小子带着心爱的 Python 菇凉,去了一趟浪漫的土耳其,然后一起又去了东京和巴黎,接着 Python 菇凉自己又去了云南的大理. 就在昨天,Pyt ...

  10. js生成一个指定范围内的随机整数

    function __random(start=0, end=1) { return Math.floor(Math.random() * (end - start + 1) + start); } ...