C++初始化与赋值 区别

转载 2013年12月04日 19:02:48

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

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语言中的初始化,都是用花括号进行,简单美观:
int array[] = {1,2,3,4,5};
struct Point point = {23};
struct Point arrPoint[] = 
{
  {
2,3},
  {
4,5},
  {
6,7}
};

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

Param param 
= {2,3}; // ERROR
Param param = {2,3,4}; //ERROR
   无法初始化。而如果不初始化的话,所有的成员而处于无政府状态,这显然很不让人放心。于是,C++提供了专门用于Class的初始化方式--构造函数:
class Param
{
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;
   有了构造函数,可以在构造函数的初始化列表中对成员进行初始化。可是很明显,这里头还是有一个陷阱,默认构造初始化和非默认构造初始化的调用方式是不一致的。默认构造函数不能用括号来调用,否则编译器将会发疯:
Param param();
   它会把上面的语句看成是函数声明,而后面调用的时候就会出错,而错误信息可能会让你抓狂一下。但是这样也就算了,偏偏 new 可以接受有括号和没括号两种写法:
Param* p1 = new Param;
Param
* p2 = new Param();
   再来说说初始化列表。初始化列表,事实上,也只能支持简单的标量类型,诸如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库,至少现在可以初始化了: 
vector<int> arr = list_of(1)(2)(3)(4);   

typedef boost::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;
+= 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 lists Initializer Lists for Standard Containers Initializer lists WP wording 等草案就是为了这个目的服务的。
   如果使用C++0x,那么程序的初始化将变得清晰和一致:
complex<double> z = {1,2}; 
//
complex<double> z {1,2}; 
// 初始化中,有等号和无等号都是允许的,下同。
+= {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++中, 对于简单类型的赋值和初始化的区别基本可以忽略,但当涉及到类或者复杂的数据类型时,问题就变得不那么简单了。 class Point { public: Point(int a=0, int...
  • linchere
  • linchere
  • 2015年01月01日 16:01
  • 507

C++构造函数初始化列表与构造函数中的赋值的区别

C++构造函数初始化列表与赋值
  • chenlycly
  • chenlycly
  • 2016年12月10日 15:16
  • 1213

初始化与赋值之间的区别

由于在内置类型中,初始化和赋值不进行区分并不会造成很大的影响,所以让我很大程度上忽略了他们的差别。   直到C++primer中对于构造函数提出了一句话,构造函数有一个初始化部分和一个函数体,在一个构...
  • ysayk
  • ysayk
  • 2016年03月28日 21:25
  • 2000

CC++结构体初始化与赋值

1.CC++结构体的初始化今天看到项目中对自定义结构体初始化方式有点陌生,特在此罗列一下可用的结构体初始化的方式。对结构体struct A { int b; int c; }有几种初始...
  • K346K346
  • K346K346
  • 2016年05月30日 13:28
  • 18749

C++ 直接初始化与赋值初始化,讲的很仔细

一、我的问题是关于初始化C++类成员的。我见过许多这样的代码:  CSomeClass::CSomeClass()  {  x=0;  y=1;  }  而在别的什...
  • taoqilin
  • taoqilin
  • 2016年08月18日 15:17
  • 3116

初始化与赋值的区别

1,初始化与赋值 初始化是从无到有的过程,先分配空间,然后再填充数据; 赋值是对己有的对象进行操作。 对于基本数据类型,二者是没有任何区别,对于非基本数据类型,在写法与效率上有许多不同。 me...
  • mao_2110901055
  • mao_2110901055
  • 2015年04月24日 15:58
  • 1004

构造函数之显式初始化与赋值

大部分程序员写构造函数时是这样的:class ClassA { ClassA(); ...... };ClassA::ClassA() { A=1; B=2; ...
  • f1121814098
  • f1121814098
  • 2017年01月02日 20:00
  • 211

C++字符数组(定义和初始化、赋值和引用)

char c[6];//发现这里无论定义多长用strcat会扩充数组大小 c[0]='C'; c[1]='h';c[2]='i';c[3]='n';c[4]='a';c[5]='\0'; //不加...
  • e_wsq
  • e_wsq
  • 2013年11月05日 00:11
  • 3217

c++ struct 初始化相关的问题分析

struct在平常应用中使用的广泛。使用中还是需要几点注意的。 0x01      首先,说一下结构体中指针初始化的问题。        平常的使用中,可能不怎么注意结构体的初始化问题,因为不去初...
  • chenzy945
  • chenzy945
  • 2015年08月15日 12:36
  • 1010

c++里的初始化,申明,定义,赋值

#include using namespace std;void func(int a);//声明 class X { private: int a; public: ...
  • feng__shuai
  • feng__shuai
  • 2017年03月27日 11:39
  • 139
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++初始化与赋值 区别
举报原因:
原因补充:

(最多只允许输入30个字)