V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
Tony042
V2EX  ›  问与答

关于 C++类的隐式转化问题

  •  1
     
  •   Tony042 · 2019-08-12 22:18:27 +08:00 · 1090 次点击
    这是一个创建于 1930 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大家好,我又来提问关于 C++的问题了,我构造了一个类,这个类有自己的构造函数,和 copy assignment construtor。这个类的具体代码如下:

    class HasPtr
    {
        friend void swap(HasPtr &, HasPtr &);
    
    public:
        void show() { cout << *ps << endl; }
        HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { cout << "string constructor" << endl; }
        // HasPtr(const char *s) : ps(new std::string(s)), i(0) { cout << "char constructor" << endl; }
        HasPtr(const HasPtr &orig) : ps(new string(*orig.ps)), i(orig.i) {}
        string GetString() { return *ps; };
        HasPtr &operator=(HasPtr);
        ~HasPtr()
        {
            delete ps;
        }
    
    private:
        std::string *ps;
        int i;
    };
    
    HasPtr &HasPtr::operator=(HasPtr hp)
    {
        swap(*this, hp);
        return *this;
    }
    
    inline void swap(HasPtr &lhs, HasPtr &rhs)
    {
        cout << "swap" << endl;
        using std::swap;
        swap(lhs.ps, rhs.ps);
        swap(lhs.i, rhs.i);
    }
    

    我发现使用构造函数时是可以正常触发从 const char* 到 string 的隐式转换,但是使用=号的时候却不可以,使用=号触发隐式转换的时候必须再加一个参数是 const char*的构造函数。

    HasPtr hp1("Hello World!") // OK, 首先 const char* 隐式转换到 string 再调用 HasPtr 构造函数
    HasPtr hp2 = "Hello World!" //  编译错误,无法将 const char* 转换到 string,所以 Hello World 无法隐式转换到 HasPtr!
    

    同样是进行隐式转换, 为什么第二个就错了呢,对于第二个我的理解是,首先调用 copy assignment operator 这个函数,然后发现要将"Hello World"隐式转换到 HasPtr,这时候编译器发现最接近的构造函数是参数为 string 的那个,然后再触发"Hello World"到 string 的隐式转换最后调用 HasPtr 的构造函数构造 HasPtr 对象,再将右操作数赋值至左边,完成整个赋值。我这样是不是太强编译器所难了?

    同时我发现如果添加一个 const char*的构造函数,就可以实现从 C 字符串到 HasPtr 对象的转化了,所以我上面思考的隐式转换顺序错在哪里了呢?

    HasPtr::HasPtr(const char *s) : ps(new std::string(s)), i(0) {}
    HasPtr = "Hello World" //编译通过!
    
    3 条回复    2019-08-12 23:32:17 +08:00
    lcdtyph
        1
    lcdtyph  
       2019-08-12 23:13:58 +08:00   ❤️ 1
    第二种初始化方式是 copy initialization,可以看这里 https://en.cppreference.com/w/cpp/language/copy_initialization
    copy initialization 必须提供可以直接隐式转换成目标类型的表达式。在你的例子里需要转换两次,所以不行。

    第一种初始化方式叫 direct initialization,它没有这个限制。
    sosilver
        2
    sosilver  
       2019-08-12 23:15:53 +08:00 via Android   ❤️ 1
    隐式类型转换最多只有一次
    choury
        3
    choury  
       2019-08-12 23:32:17 +08:00   ❤️ 1
    可以加 explicit 禁止隐式转换
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   920 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 22:18 · PVG 06:18 · LAX 14:18 · JFK 17:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.