(转)C++初始化与赋值
来源:http://www.cnblogs.com/chio/archive/2008/10/06/1305145.html
先来个区别说明:赋值操作是在两个已经存在的对象间进行的,而初始化是要创建一个新的对象,并且其初值来源于另一个已存在的对象。编译器会区别这两种情 况,赋值的时候调用重载的赋值运算符,初始化的时候调用拷贝构造函数。如果类中没有拷贝构造函数,则编译器会提供一个默认的。这个默认的拷贝构造函数只是 简单地复制类中的每个成员。 下面看例子。
c++中初始化和赋值操作差别是很大的。
对于基本数据类型差别不大:
比如:
int a = 12; // initialization, copy 0X000C to a
a = 12; // assignment, copy 0X000C to a
但是对用户自定义的数据类型比如String 初始化和赋值就差别很大:
class String ...{
public:
String( const char *init ); // intentionally not explicit!
~String();
String( const String &that );
String &operator =( const String &that );
String &operator =( const char *str );
void swap( String &that );
friend const String // concatenate
operator +( const String &, const String & );
friend bool operator <( const String &, const String & );
//...
private:
String( const char *, const char * ); // computational
char *s_;
};
初始化的构造过程比较简单:先分配一个足够大的空间然后填充上数据:
String::String( const char *init ) ...{
if( !init ) init = """";
s_ = new char[ strlen(init)+1 ];
strcpy( s_, init );
}
析构过程更简单:
String::~String() ...{ delete [] s_; }
但是如果赋值操作就复杂多了:
String &String::operator =( const char *str ) ...{
if( !str ) str = """";
char *tmp = strcpy( new char[ strlen(str)+1 ], str ); // 多了中间变量
delete [] s_; // 多了删除s_;
s_ = tmp; // 多一个赋值操作!现在是指向字符的指针,如果是个大对象,效率的差别可想而知.
return *this;
}
C++初始化语法的不一致性:
C语言确实很优雅,整个语言的设计简洁一致。而在C++中,有一个让人诟病的问题就是变量初始化的不一致性。
C语言中的初始化,都是用花括号进行,简单美观:
struct Point point = {2, 3};
struct Point arrPoint[] =
{
{2,3},
{4,5},
{6,7}
};
C++自然也兼容了C语言的初始化机制。然而,C++的Class乃至STL都不支持。它们要用不同的方式来初始化, 甚至根本不能够直接初始化, 只能使用运行时的赋值。
比如Class:
{
public:
int Age;
int Value;
private:
int Level;
};
Param param = {2,3}; // ERROR
Param param = {2,3,4}; //ERROR
无法初始化。而如果不初始化的话,所有的成员而处于无政府状态,这显然很不让人放心。于是,C++提供了专门用于Class的初始化方式--构造函数:
{
public:
Param(int x, int y)
: x_(x), y_(y)
{}
Param()
: x_(0), y_(0)
{}
private:
int x_, y_;
};
Param param(1,2);
//或
Param param;
有了构造函数,可以在构造函数的初始化列表中对成员进行初始化。可是很明显,这里头还是有一个陷阱,默认构造初始化和非默认构造初始化的调用方式是不一致的。默认构造函数不能用括号来调用,否则编译器将会发疯:
它会把上面的语句看成是函数声明,而后面调用的时候就会出错,而错误信息可能会让你抓狂一下。但是这样也就算了,偏偏 new 可以接受有括号和没括号两种写法:


再来说说初始化列表。初始化列表,事实上,也只能支持简单的标量类型,诸如int,bool,指针之类的;复杂点的,如数组、结构,不好意思,不支 持--只能在构造函数体中进行赋值。还有一个很迷糊初学者的问题是,成员初始化的顺序仅依赖于成员定义的顺序,而不是初始化列表中的顺序。
再比如STL容器,这下好象更惨,连构造函数都帮不上忙了,除了初始化一个空的容器,或是复制一下别的容器,我们只能做用默认构造函数进行初始化。我们拿数组和vecotr做个比较:
int arr[]={1,2,3,4};
// vector
vector<int> iarr;
// 必须在某个函数中赋初值
void init()
{
for(int i = 1; i <= 4; ++i)
iarr.push_back(i);
}
再复杂一点的数据结构,那单单赋值程序就要写上老长,而且还不好看。还要记得调用。这对于仅仅是简单的设置一些初值的用途来说,太过于烦琐。
横向比较,这次好象C++还不会太落伍,只有C和动态语言提供了初始化特性,其它支持OO高级语言好象都是学C++的。如Java, C#(注C#3.0开始提供初始化功能)...
C++能不能做到简洁一致的实始化呢?
Boost的assign库做了许多有益的工作。使用assign库,至少现在可以初始化了:








如果是赋值,也可以简略很多:



不过,也仅能如此了。assign经过许多努力,也仅能支持容器的初始化,而且还不够漂亮。
C++0x已确定提供与C一致的初始化功能。 Initialer lists Initializer Lists for Standard Containers Initializer lists WP wording 等草案就是为了这个目的服务的。
如果使用C++0x,那么程序的初始化将变得清晰和一致:
//或
complex<double> z {1,2};
// 初始化中,有等号和无等号都是允许的,下同。
z += {2,3};
int a = {1};
new vector<string>{"once", "upon", "a", "time"};
f( {"Nicholas", "Annemarie"} ); // 参数是两个元素的列表
return { "Norah" }; // 返回只有一个元素的列表
int* e {}; // 初始化为0或NULL指针
map<string,int> anim =
{
{"bear",4},
{"cassovary",2},
{"tiger",7}
};
这好象是C++欠了十多年的债吧。
(转)C++初始化与赋值的更多相关文章
- 百度编辑器ueditor 异步加载时,初始化没办法赋值bug解决方法
百度编辑器ueditor 异步加载时,初始化没办法赋值bug解决方法 金刚 前端 ueditor 初始化 因项目中使用了百度编辑器——ueditor.整体来说性能还不错. 发现问题 我在做一个编辑页面 ...
- C++ 初始化与赋值
1.初始化与赋值的区别: 二者的区别不是看,是否有=这个赋值操作符,而是看操作的时候,对象是否已经有值. 初始化:创建对象,并给它设置初始值. 赋值:对象已经有值,擦除对象的当前值,并使用新值代替. ...
- C语言指针的初始化和赋值
1.指针的初始化 指针初始化时,"="的右操作数必须为内存中数据的地址,不能够是变量,也不能够直接用整型地址值(可是int*p=0;除外,该语句表示指针为空).此时,*p仅仅是表示 ...
- c/c++ 标准容器 之 初始化, 赋值, swap, 比较
c/c++ 标准容器 之 初始化, 赋值, swap, 比较 知识点 1,容器的初始化,对应代码里的test1 2,标准库array的初始化,对应代码里的test2 3,容器的赋值 ,对应代码里的te ...
- GO学习笔记 - 变量在定义时没有明确的初始化时会赋值为“零值 ”。
官方教程:https://tour.go-zh.org/basics/12 变量在定义时没有明确的初始化时会赋值为 零值 . 零值是: 数值类型为 0 , 布尔类型为 false , 字符串为 &qu ...
- C语言结构体数组内带字符数组初始化和赋值
1.首先定义结构体数组: typedef struct BleAndTspRmtCmd{ char terminal[3]; char note[3]; char rmtCmd[10]; char c ...
- c++构造函数成员初始化中赋值和初始化列表两种方式的区别
先总结下: 由于类成员初始化总在构造函数执行之前 1)从必要性: a. 成员是类或结构,且构造函数带参数:成员初始化时无法调用缺省(无参)构造函数 b. 成员是常量或引用:成员无法赋值,只能被初始化 ...
- c++构造函数问题,初始化和赋值问题
默认构造函数(就是没有参数的构造函数) The Default ConstructorThe default constructor is the constructor used to create ...
- PHP变量的初始化以及赋值方式介绍
什么是变量 变量通俗的来说是一种容器.根据变量类型不同,容器的大小不一样,自然能存放的数据大小也不相同.在变量中存放的数据,我们称之为变量值. PHP 中的变量用一个美元符号后面跟变量名来表示.变量名 ...
随机推荐
- 总是有个yumBackend.py阻止我用yum进行更新
[Another app is currently holding the yum lock; waiting for it to exit...] 上网查了,好像是说帮我安个桌面图标的进程. 估计是 ...
- python-day41--约束条件
一 .介绍 约束条件与数据类型的宽度一样,都是可选参数 作用:用于保证数据的完整性和一致性主要分为: PRIMARY KEY (PK) 标识该字段为该表的主键,可以唯一的标识记录 FOREIGN KE ...
- CoderForce 140C-New Year Snowmen(贪心)
题目大意:有n个已知半径的雪球.堆一个雪人需要三个尺寸不同的雪球,问用这些雪球最多能堆多少个雪人? 题目分析:先统计一下每种尺寸的球的个数,从三种最多的种类中各取出一个堆成雪人,这样贪心能保证的到的数 ...
- juqery的一些简单用法
层级选择器(重点).基本过滤选择器 :eq(index) 选择匹配到的元素中索引号为index的一个元素,index从0开始 :odd 选择匹配到的元素中索引号为奇数的所有元素,index从0开始 : ...
- JS水平移动图片
横向: <div id=demo style="overflow:hidden;width:200px;border:2px solid #e0e0e0;padding:2px;&qu ...
- 信号处理函数的返回sigsetjmp/siglongjmp
由于在信号处理期间自动屏蔽了正在被处理的信号,而使用setjmp/longjmp跳出信号处理程序时又不会自动将 信号屏蔽码修改会原来的屏蔽码,从而引起该信号被永久屏蔽. 可以使用sigsetjmp/s ...
- winRAR显示树树目录
这样 比较方便
- 太过亲密往往不好——用non-member,non-friend替换member函数
在前一篇文章,我们提到,使用private来代替public以提高class的封装性.这一篇文章,我们将对接口发起攻势.首先来个简单的例子. class WebBrowser { public: vo ...
- 关于这个 SDK.InvalidRegionId : Can not find endpoint to access
String product = "Dysmsapi";//短信API产品名称(短信产品名固定,无需修改) TM 调试了半天,一直报错.原来是因为我改了上面的 Dysm ...
- ADOX创建ACCESS 表时,几个附加属性
中文 英文 允许空字符串 Jet OLEDB:Allow Zero Length Unicode压缩 Jet OLEDB:Compressed UNICODE Strings 有效性规则 Jet ...