• [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(); }
  • 相关阅读:
    侯捷——c++面向对象思维(二)引用
    一道立体几何大题求体积问题
    云数据中心和传统数据中心的区别
    统信故障处理记录忘记登录密码/输错次数过多被锁定
    简单解决github.com 无法访问的问题
    linux 安装composer
    20191214Exp2后门原理与实践
    hash碰撞实例(选做)
    EXP3免杀原理与实践
    环境准备及spring源码下载并导入IDEA
  • 原文地址:https://www.cnblogs.com/SelaSelah/p/2729314.html
Copyright © 2020-2023  润新知