`
tubaluer
  • 浏览: 1443608 次
文章分类
社区版块
存档分类
最新评论
  • sblig: c / c++ 是不一样的都会输出 100
    j = j++

C++初始化与赋值

 
阅读更多

摘自:http://student.csdn.net/link.php?url=http://www.cnblogs.com%2Fchio%2Farchive%2F2008%2F10%2F06%2F1305145.html

C++初始化与赋值

先来个区别说明:赋值操作是在两个已经存在的对象间进行的,而初始化是要创建一个新的对象,并且其初值来源于另一个已存在的对象。编译器会区别这两种情 况,赋值的时候调用重载的赋值运算符,初始化的时候调用拷贝构造函数。如果类中没有拷贝构造函数,则编译器会提供一个默认的。这个默认的拷贝构造函数只是 简单地复制类中的每个成员。下面看例子。

c++中初始化和赋值操作差别是很大的。
对于基本数据类型差别不大:
比如:
inta=12;//initialization,copy0X000Ctoa
a=12;//assignment,copy0X000Ctoa
但是对用户自定义的数据类型比如String初始化和赋值就差别很大:
classString...{
public:
String(constchar*init);//intentionallynotexplicit!
~String();
String(constString&that);
String&operator=(constString&that);
String&operator=(constchar*str);
voidswap(String&that);
friendconstString//concatenate
operator+(constString&,constString&);
friendbooloperator<(constString&,constString&);
//...
private:
String(constchar*,constchar*);//computational
char*s_;
};
初始化的构造过程比较简单:先分配一个足够大的空间然后填充上数据:
String::String(constchar*init)...{
if(!init)init="""";
s_=newchar[strlen(init)+1];
strcpy(s_,init);
}
析构过程更简单:
String::~String()...{delete[]s_;}

但是如果赋值操作就复杂多了:
String&String::operator=(constchar*str)...{

if(!str)str="""";

char*tmp=strcpy(newchar[strlen(str)+1],str);//多了中间变量

delete[]s_; //多了删除s_;
s_=tmp; //多一个赋值操作!现在是指向字符的指针,如果是个大对象,效率的差别可想而知.

return*this;
}

C++初始化语法的不一致性:

C语言确实很优雅,整个语言的设计简洁一致。而在C++中,有一个让人诟病的问题就是变量初始化的不一致性。

C语言中的初始化,都是用花括号进行,简单美观:
intarray[]={1,2,3,4,5};
structPointpoint={2,3};
structPointarrPoint[]=
{
{
2,3},
{
4,5},
{
6,7}
};

C++自然也兼容了C语言的初始化机制。然而,C++的Class乃至STL都不支持。它们要用不同的方式来初始化, 甚至根本不能够直接初始化, 只能使用运行时的赋值。
比如Class:
classParam
{
public:
intAge;
intValue;
private:
intLevel;
};

Paramparam
={2,3};//ERROR
Paramparam={2,3,4};//ERROR
无法初始化。而如果不初始化的话,所有的成员而处于无政府状态,这显然很不让人放心。于是,C++提供了专门用于Class的初始化方式--构造函数:
classParam
{
public:
Param(
intx,inty)
:x_(x),y_(y)
{}
Param()
:x_(
0),y_(0)
{}
private:
intx_,y_;
};

Paramparam(
1,2);
//
Paramparam;
有了构造函数,可以在构造函数的初始化列表中对成员进行初始化。可是很明显,这里头还是有一个陷阱,默认构造初始化和非默认构造初始化的调用方式是不一致的。默认构造函数不能用括号来调用,否则编译器将会发疯:
Paramparam();
它会把上面的语句看成是函数声明,而后面调用的时候就会出错,而错误信息可能会让你抓狂一下。但是这样也就算了,偏偏 new 可以接受有括号和没括号两种写法:
Param*p1=newParam;
Param
*p2=newParam();
再来说说初始化列表。初始化列表,事实上,也只能支持简单的标量类型,诸如int,bool,指针之类的;复杂点的,如数组、结构,不好意思,不支 持--只能在构造函数体中进行赋值。还有一个很迷糊初学者的问题是,成员初始化的顺序仅依赖于成员定义的顺序,而不是初始化列表中的顺序。

再比如STL容器,这下好象更惨,连构造函数都帮不上忙了,除了初始化一个空的容器,或是复制一下别的容器,我们只能做用默认构造函数进行初始化。我们拿数组和vecotr做个比较:
//数组
intarr[]={1,2,3,4};
//vector
vector<int>iarr;
//必须在某个函数中赋初值
voidinit()
{
for(inti=1;i<=4;++i)
iarr.push_back(i);
}

再复杂一点的数据结构,那单单赋值程序就要写上老长,而且还不好看。还要记得调用。这对于仅仅是简单的设置一些初值的用途来说,太过于烦琐。

横向比较,这次好象C++还不会太落伍,只有C和动态语言提供了初始化特性,其它支持OO高级语言好象都是学C++的。如Java, C#(注C#3.0开始提供初始化功能)...

C++能不能做到简洁一致的实始化呢?
Boost的assign库做了许多有益的工作。使用assign库,至少现在可以初始化了:
vector<int>arr=list_of(1)(2)(3)(4);

typedefboost::tuple
<int,std::string,int>tuple;
vector
<tuple>v=tuple_list_of(1,"foo",2)(3,"bar",4);

map
<int,int>next=map_list_of(1,2)(2,3)(3,4)(4,5)(5,6);

stack
<string>names=list_of("Mr.Foo")("Mr.Bar")("Mrs.FooBar").to_adapter();
如果是赋值,也可以简略很多:
vector<int>v;
v
+=1,2,3,repeat(10,4),5,6,7,8,9;
//v=[1,2,3,4,4,4,4,4,4,4,4,4,4,5,6,7,8,9]
不过,也仅能如此了。assign经过许多努力,也仅能支持容器的初始化,而且还不够漂亮。

C++0x已确定提供与C一致的初始化功能。 Initialer listsInitializer Lists for Standard ContainersInitializer lists WP wording等草案就是为了这个目的服务的。
如果使用C++0x,那么程序的初始化将变得清晰和一致:
complex<double>z={1,2};
//
complex<double>z{1,2};
//初始化中,有等号和无等号都是允许的,下同。
z+={2,3};

inta={1};

newvector<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++全局变量只能初始化不能赋值的问题

    声明、初始化与赋值的区别: 声明:int a; 初始化:int a = 2;(在声明的时候顺带赋值叫做初始化) 赋值:a = 2; 只有定义(int a;)才分配存储空间,初始化必须要有存储空间来初始化 全局变量在声明时候顺带赋值...

    C++初始化列表使用

    讲解了为什么要初始化列表,初始化列表和在构造函数中赋值的区别

    c++结构体的初始化和赋值1

    这里只列出了两个对象的初值,所以第三个对象中的数据成员分别被初始化为对应数据类型的缺省初值① 2&gt;对于包含数组的结构体来说,初始化与上述类似,需要说明的一点是,

    浅谈c++构造函数问题,初始化和赋值问题

    下面小编就为大家带来一篇浅谈c++构造函数问题,初始化和赋值问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    成员初始化列表与构造函数体中的区别详细解析

    C++ Primer中在讲构造函数初始化列表的时候有这么一段话:无论是在构造函数初始化列表中初始化成员,还是在构造函数体中对它们赋值,最终结果是相同的。不同之处在于,使用构造函数初始化列表的版本初始化数据成员,...

    C++初始化函数列表详细解析

    对于类成员是const修饰,或是引用类型的情况,是不允许赋值操作的,(显然嘛,const就是防止被错误赋值的,引用类型必须定义赋值在一起),因此只能用初始化列表对齐进行初始化。成员类型是没有默认构造函数的类。若...

    C++ 初始化列表详解及实例代码

    与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段。在C++中,struct和class的唯一区别是默认的访问性不同,而这里我们不...

    C++直接初始化和复制初始化

    现在正式对C++中对象建立和初始化做一个总结。  (1)复制初始化的基本原理  我们知道,对象在内存中的直接表象是在内存中占有一个一定大小的空间。分配空间是建立对象的第一步。但是刚刚分配的空间像一个没有...

    详解C++中变量的初始化规则

    除了用作赋值操作的左操作数,其他任何使用未初始化变量的行为都是未定义的,不要依赖未定义行为。 以int类型为例,一段简单的测试代码: #include using namespace std; int a; int main() { int b; cout &lt;&...

    C语言二维数组的定义、初始化、赋值.pdf

    C++

    c++ 类中const成员变量的赋值方法

    1、类定义中不能进行初始化,因为头文件中类的定义只是一个声明,并没有分配真正空间,因此变量是不存在的,因此是不能赋值的。 2、const 定义的变量是不能赋值 这可如何是好,声明中不能赋值,声明完还不能赋值。又...

    C++之STL的vector详解,包括初始化和各种函数:vector的初始化、数据的增删查改等

    二、vector的初始化-赋值 1、.assign(beg, end) 赋值操作 2、.assign(n, elem) 赋值操作 3、重载等号操作符 operator= 4、直接列表初始化 `Vector&lt;T&gt; {,};` 5、swap 函数 三、数据的增删查改 1、at(int id)接口 2、...

    C++ 赋值构造函数注意点介绍

    您可能感兴趣的文章:浅谈c++构造函数问题,初始化和赋值问题详解C++ 拷贝构造函数和赋值运算符详解C++中对构造函数和赋值运算符的复制和移动操作C++中复制构造函数和重载赋值操作符总结深入C++中构造函数、拷贝构造...

    C++ 构造函数初始化列表的好处

    C++ 类对像构造时,需要对类成员变量完成初始化赋值操作。使用初始化列表完成这步操作在性能上有益处。什么好处呢?摆道理显得不够彻底。看书不如做实验。让我们结合执行过程来查看。考虑如下示例代码:  ...

    C++中静态初始化数组与动态初始化数组详解

    今天小编就为大家分享一篇C++中静态初始化数组与动态初始化数组详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

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

    构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的...而没使用初始化列表的构造函数是对类的成员赋值,并没有进行显式的初始化。  初始化和赋值对内置类型的

    NDK13_C++基础:构造函数、拷贝构造函数、浅拷贝与深拷贝.zip

    C++中 这个语句执行完毕,在当前的堆内存内 初始化并且赋值好该对象 在java中执行这个语句,只是开辟了一块内存空间,并没初始化和赋值对象, 必须用new关键字,来进行初始化和赋值 ——————————————...

    详谈C++何时需要定义赋值/复制构造函数

    继承和动态内存分配 ...对于构造函数,这是通过在初始化成员列表中调用基类的复制构造函数来完成的,如果不这样做,将自动调用基类的默认构造函数,对于赋值运算符,这是通过使用域解析运算符显示地调用基

Global site tag (gtag.js) - Google Analytics