C++ 对象的初始化
C++中变量初始化包括三种方式:默认初始化、直接初始化、拷贝初始化。在C++中每个类都定义了对象被初始化的方式,构造函数的任务是初始化类的数据成员,只要类的对象被创造就会执行构造函数。
一个类被创建出来即使什么东西都不定义,编译器也会为我们生成下面的4个函数:
- 默认构造函数(default constructor)
- 析构函数(destructor)
- 拷贝构造函数(copy constructor)
- 拷贝赋值操作符(copy-assignment operator)
默认初始化
默认初始化依赖于默认构造函数。
默认构造函数(default constructor)
默认构造函数无须任何实参,如果一个类没有显示定义构造函数,则编译器会隐式地定义一个默认构造函数,称为合成的默认构造函数(synthesized default constructor),但是合成默认构造函数可能会失效,对于任何类都应定义默认构造函数。
构造函数初始值列表(cosntructor initializer list)
对于构造函数,建议使用初始值列表,例如对于下面这个类:
class A{
private:
int i;
double j;
public:
/*...*/
}
有下面两种构造函数的写法:
A():i(0),j(0){}//列表初始化,直接将i、j显示地初始化为0,相当于拷贝构造函数,对内置类型直接拷贝,对类类型使用该类的拷贝构造函数
A():{i=0;j=0;}//先将i、j默认初始化再将i、j赋值为0
第二种写法会先进行默认初始化再进行赋值,如果有些成员无法默认初始化(例如引用&和常量const)只能显示地初始化则会造成错误,因而建议都使用列表初始化以防止出错。
直接初始化和拷贝初始化
当用于类类型对象时,初始化的拷贝形式和直接形式有所不同:直接初始化直接调用与实参匹配的构造函数,拷贝初始化总是调用拷贝构造函数。拷贝初始化首先使用指定构造函数创建一个临时对象,然后用拷贝构造函数将那个临时对象拷贝到正在创建的对象。
拷贝构造函数(copy construcor)
拷贝构造函数的声明为classname(const classname &op),与合成默认构造函数不同,即使我们定义了其他构造函数,编译器也会为我们合成一个拷贝构造函数。例如我们在自定义的类内声明了一个形参为(const)classname 的构造函数,例如对于下面的类:
class A{
private:
int i;
public:
A():i(0){}
A(A op){i}
}
则编译器会提示:[Error] invalid constructor; you probably meant 'A (const A&)',说明编译器已经默认创建了声明为A(const A &)的拷贝构造函数,即合成拷贝构造函数(synthesized copy constructor),一般合成拷贝构造函数会将其参数的成员诸葛拷贝到正在创建的对象中,对类类型的成员使用该类的拷贝构造函数来拷贝,而内置类型的成员则是直接拷贝。
区分拷贝初始化和直接初始化
使用直接初始化时,我们实际上时要求编译器使用普通的函数匹配来选择与我们提供的参数最匹配的构造函数;而使用拷贝初始化时,我们要求编译器将右侧运算对象通过拷贝构造函数拷贝到正在创建的对象中。
关于拷贝构造函数和拷贝赋值运算符
拷贝赋值运算符本质上是一个函数。一般情况下我们总是以为在=运算符出现的地方都是调用copy assignment operator,但是当一个新对象被定义的时候,即便这个时候是使用了'='运算符,它真实调用的是初始化函数copy constructor,而不是调用copy assignment operator去进行赋值操作。
class A{
/*...*/
}
A a;//默认初始化
A b(a);//拷贝初始化
A c=a;//虽然使用了=运算符,但是此处调用的时A(const A &)即拷贝构造函数
A d;//默认初始化
d=a;//这里才是使用了拷贝赋值运算符,是赋值
何时发生拷贝初始化
- 将一个对象作为实参传递给一个非引用类型的形参。
- 从一个返回类型为非引用类型的函数返回一个对象。
- 用花括号列表初始化一个数值中的元素或一个聚合类中的成员。
以例代文
为了更好地理解三种初始化方式,使用下面这个例子
#include<cstdio>
#include<iostream>
using namespace std;
class A{
private:
int i;
int j;
public:
A()//默认构造函数
{cout<<" A()"<<endl;}
A(const A &)//拷贝构造函数
{cout<<" A(const A&)"<<endl;}
A& operator =(const A &)//拷贝赋值操作符
{cout<<" A &operator =(const A &)"<<endl;}
A(int k)//
{cout<<" A(int k)"<<endl;}
A(int k,int m)
{cout<<" A(int k,int m)"<<endl;}
};
A func(A temp){
return temp;
}
int main()
{
cout<<"p1:"<<endl;
A p1;//默认初始化
cout<<"p2:"<<endl;
A p2(1);//直接初始化
cout<<"p3:"<<endl;
A p3(1,2);//直接初始化
cout<<"p4:"<<endl;
A p4=1;//被编译器优化为A p4(1),直接初始化
cout<<"p5:"<<endl;
A p5(p1);//拷贝初始化
cout<<"p6:"<<endl;
A p6=p1;//仍然时拷贝初始化,虽然使用了=
cout<<"p7:"<<endl;
A p7;//先默认初始化
p7=p1;//使用了拷贝赋值运算符,是赋值
cout<<"p8:"<<endl;
A p8;//默认初始化
p8=func(p1);//较复杂下面分析
return 0 ;
}
得到运行结果
p1:
A()//默认初始化
p2:
A(int k)//直接初始化
p3:
A(int k,int m)//直接初始化
p4:
A(int k)//被编译器优化为A p4(1),直接初始化
p5:
A(const A&)//拷贝初始化
p6:
A(const A&)//仍然时拷贝初始化,虽然使用了=
p7:
A()//先默认初始化
A &operator =(const A &)//使用了拷贝赋值运算符,是赋值
p8:
A()//先默认初始化
A(const A&)//将一个对象作为实参传递给一个非引用类型的形参,发生拷贝初始化,将temp拷贝初始化为p1
A(const A&)//从一个返回类型为非引用类型的函数返回一个对象,当func函数结束时要将返回值拷贝到临时对象,执行拷贝初始化
A &operator =(const A &)//将临时对象通过拷贝赋值运算符赋值给p8
//注意这个时候有可能会被编译器优化!
C++ 对象的初始化的更多相关文章
- 解析Java类和对象的初始化过程
类的初始化和对象初始化是 JVM 管理的类型生命周期中非常重要的两个环节,Google 了一遍网络,有关类装载机制的文章倒是不少,然而类初始化和对象初始化的文章并不多,特别是从字节码和 JVM 层次来 ...
- java中类的初始化和对象的初始化
静态的属于全局静态区,这个部分独立存在,不管是成员还是块,都是静态的,大家地位相等,先到先得. 然后是成员初始化,这个部分在类的构造函数前初始化,因为编译器(或者设计者)可能认为构造函数调用了这个成员 ...
- ios中属性和对象的初始化
属性和对象的初始化为了方便记忆, 我们可以都使用self.来初始化. 这样可以避免内存的过度释放.
- [C#解惑] #2 对象的初始化顺序
谜题 在上一篇C#解惑中,我们提到了对象的初始化顺序.当我们创建一个子类的实例时,总是会先执行基类的构造函数,然后再执行子类的构造函数.那么实例字段是什么时候初始化的呢?静态构造函数和静态字段呢?今天 ...
- JAVA基础之对象的初始化
本文主要记录JAVA中对象的初始化过程,包括实例变量的初始化和类变量的初始化以及 final 关键字对初始化的影响.另外,还讨论了由于继承原因,探讨了引用变量的编译时类型和运行时类型 一,实例变量的初 ...
- [百度空间] [转] 在 Visual C++ 中控制全局对象的初始化顺序
from: http://blog.csdn.net/classfactory/archive/2004/08/07/68202.aspx 在 C++ 中,同一个翻译单位(.cpp文件)里的全局对象的 ...
- C++:对象的初始化和构造函数
对象的初始化和构造函数 构造函数:是一种特殊的成员函数,它主要用于为对象分配空间,进行初始化.构造函数 的名字必须与类名相同,它不要用户来调用,而是在建立对象时自动执行的 形式一: 类名 对象名(实参 ...
- Java反射机制(获取Class对象的三种方式+获取Class中的构造函数进行对象的初始化+获取反射类的字段+获取反射类的一般方法)
反射技术其实就是动态加载一个指定的类,并获取该类中的所有内容.而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员,简单来说:反射技术可以对一个类进行解剖,反射大大增强 ...
- 重新开始学习javase_对象的初始化
一.类加载机制 类加载的时机类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载.验证.准备.解析.初始化.使用.卸载7的阶段: 加载.验证.准备.初始化和卸载这5个阶段的顺序是 ...
- C#高级知识点概要(3) - 特性、自动属性、对象集合初始化器、扩展方法、Lambda表达式和Linq查询
1.特性(Attributes) 特性(Attributes),MSDN的定义是:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法 ...
随机推荐
- JavaScript 基础 学习 (一)
JavaScript 基础 学习 获取页面中的元素的方法 作用:通过各种方式获取页面中的元素 比如:id,类名,标签名,选择器 的方式来获取元素 伪数组: 长的和数组差不多,也是按照索引排 ...
- 媳妇儿让我给她找一个PDF转word免费工具,找了半天我决定给她写一个出来^-^
之前我媳妇儿让我给她找一个PDF转WORD的免费工具,在网上找了半天发现要不就是收费,要不就是转化的格式混乱.既然网上不能找到好用的免费工具那就直接来写一个吧.人生苦短,我用python. 万能的 ...
- oracle 12c数据库在Windows环境下的安装
因为菜鸟小白之前做着一些数据库审计产品的测试,接下来我会分享一些关于数据库安装和通过python的访问数据库的知识 安装 首先我们需要下载一个oracle 12c的安装程序,解压后右键点击“ ...
- 【Python学习笔记七】从配置文件中读取参数
将一些需要更改或者固定的内容存放在配置文件中,通过读取配置文件来获取参数,这样修改以及使用起来比较方便 1.首先是配置文件的写法如下一个environment.ini文件: 里面“[]”存放的是sec ...
- Atlassian Confluence 5.1.2 破解版部署
Atlassian Confluence(简称Confluence)是一个专业的wiki程序.它是一个知识管理的工具,通过它可以实现团队成员之间的协作和知识共享.Confluence 不是一个开源软件 ...
- 仔细想想SpringAOP也不难嘛,面试没有必要慌
文章已托管到GitHub,大家可以去GitHub查看阅读,欢迎老板们前来Star! 搜索关注微信公众号 码出Offer 领取各种学习资料! LOGO SpringAOP 一.什么是AOP AOP(As ...
- 学会Python除了不能生孩子,其他的都能做。
随着人工智能的迅猛发展,相信大家对于it行业最熟悉的词莫过于 Python.那么,Python究竟可以做些什么呢?一个资深程序员说:“学会Python除了不能生孩子,其他的都能做.”加入3137821 ...
- 题解 洛谷 P1552 【[APIO2012]派遣】
根据题意,我们不难发现忍者之间的关系是树形结构. 发现答案的统计只是在该节点的子树中,因此我们考虑通过树形\(DP\)来解决问题. 从叶子节点开始,从下往上考虑,因为一个节点的最优答案只与他的领导力和 ...
- Webpack前世今生
在正式介绍Webpack之前,先给大家说明一下前端为什么需要模块化 1.为什么需要模块化 1.1JS原始功能 在网页开发的早期,js制作作为一种脚本语言,做一些简单的表单验证或动画实现等,那个时候代码 ...
- springMVC -- 对接UEditor(富文本编辑器)
工作中需要用到UEditor编辑文本,在与springMVC进行整合时,出现了一些问题,结果导致,在进行图片上传时出现如下提示: 上网查询了很多相关资料,此处简要记录下,防止以后遇到类似问题. 一种方 ...