[C++]“=”详解

引言

C++的“=”实际有很多很多陷阱。

在大部分情况下,“=”表示赋值,尤其是C语言学过来的,更有这样的体会。以下两者的执行结果是等效的:

// 示例A
int a = 3;

// 示例B
int a;
a = 3;

 难免会有直观的认识,int a = 3 中,首先创建一个int的名为a的对象,然后将3赋值给a。而示例B中,将这一过程拆分成了两部。

↑↑恩,万恶的根源↑↑

C++中“=”的语义分类

“=”其实有两种作用:1. 参与构造;2. 赋值。

参与构造类似于初始化,是狭义的初始化(或者是说协助定义,异或有其他更好的说法?)——在一些场合,对从未赋值过的对象进行第一次赋值,也叫做初始化——而这里的“初始化”仅指构造完成对象的这一过程。

// 传统意义上的初始化
int a;    // 定义了一个对象←其实是内置类型,C++好绕啊=_=   
a = 3;    // 对其初始化←实际上就是赋值了而已

// 本文所说的初始化和赋值
int a;    // 定义了一个对象←其实已经构造完毕了,因为没用=,所以默认初始化的
          // 有的情况下,默认初始化为了0xCDCDCDCD
          // 有的情况下,默认初始化为了内存存放的旧值
a = 3;    // 对于赋值

以下的例子说明了int a = 3; 和 int a; a = 3; 是不一样的:

static int func1_i; // static duration变量默认为0
int func1(){
    static int i = func1_i; // 这里的=参与的是初始化
                            // 因为static的函数成员只在第一次使用时构造,
                            //所以只执行了1次
    return i++;
}

static int func2_i;
int func2(){
    static int i;           // 同上,这一句只执行1次
    i = func2_i;            // 这是赋值,每次都要执行
    return i++;
}

int main(int argc, char* argv)
{
    using namespace std;
    cout << func1();
    cout << func1() << endl; // 输出 01
    cout << func2();
    cout << func2() << endl; // 输出 0 0,因为每次都重新赋值为0
    getchar();
}

 这一问题,在C中并不显著,但是在C++却很重要,因为——C++有对象(C你就继续单身着吧)

除了赋值,还有构造

对于内置类型,是无法探寻其实现代码的,C++保证语义上符合这一归于。但是对于用户定义的类就不一样了,我们可以自己书写代码,来验证这一语义。

struct A{
    // 默认构造函数
    A() {std::printf("default ctor\n");} 
    // 隐式转换构造函数
    A(int) {std::printf("ctor with para int\n");}
    // 赋值
    A& operator=(int) {std::printf("operator=\n"); return *this;}
};

int main(int argc, char* argv)
{
    using namespace std;
    A a1;      // 输出default ctor,调用了默认构造
    a1 = 3;    // 输出operator=,调用了赋值
    A a2 = 3;  // 输出ctor with para int,调用了带参数的构造
    getchar();
}

切记,ClassA obj = value; 绝不是创建一个对象obj,然后把value赋值给obj那么简单。

注意类型转换

上边例子的赋值3,可以改为浮点数,编译器会尝试将浮点数转为整数,然后调用响应的函数。

但是,如果存在转换不了的情况,例如string到int,编译器则会报错。

struct A{
    A() {std::printf("default ctor\n");}
    A(int) {std::printf("ctor with para int\n");}
    A& operator=(int) {std::printf("operator= with para int\n"); return *this;}
// 书写了一个无法转换为int的参数的类型 A& operator=(std::string) {std::printf("operator= with para string\n"); return *this;} }; int main(int argc, char* argv) { using namespace std; string str = "str"; A a1; // 默认构造 a1 = str; // 输出operator= with para string赋值 A a3 = str; // 报错,提示没有这种类型的ctor不存在,需要一个A(string)的构造函数 getchar(); }

 

posted @ 2012-10-18 13:15  斯啦丝拉  阅读(1164)  评论(0编辑  收藏  举报