zoukankan      html  css  js  c++  java
  • [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(); }
  • 相关阅读:
    JS BOM对象 History对象 Location对象
    JS 字符串对象 数组对象 函数对象 函数作用域
    JS 引入方式 基本数据类型 运算符 控制语句 循环 异常
    Pycharm Html CSS JS 快捷方式创建元素
    CSS 内外边距 float positio属性
    CSS 颜色 字体 背景 文本 边框 列表 display属性
    【Android】RxJava的使用(三)转换——map、flatMap
    【Android】RxJava的使用(二)Action
    【Android】RxJava的使用(一)基本用法
    【Android】Retrofit 2.0 的使用
  • 原文地址:https://www.cnblogs.com/SelaSelah/p/2729314.html
Copyright © 2011-2022 走看看