如何正确使用转换构造函数?

Posted

技术标签:

【中文标题】如何正确使用转换构造函数?【英文标题】:How to correctly use converting constructors? 【发布时间】:2016-10-06 23:25:05 【问题描述】:

我读到 C++ 编译器能够在提供适合转换构造函数或操作数时隐式转换类型。 我实际上找到了看起来很像这样的示例代码:

class Dog
    private:
       string name;
    public:
        Dog(string n):name(n) //This as the converting constructor


int main()
    Dog d = "rover";

每当我运行此代码时,编译器都会抛出错误消息:

请求从“const char [6]”转换为非标量类型“Dog” 狗 d = "漫游者";

编译时我添加了编译器选项-std=c++11,所以它不应该与C++版本有关,对吧? 我在互联网上找到的示例(至少对我而言)看起来非常相似,所以我不知道这里出了什么问题。 我对这个主题的输入来自这个视频: Convert constructor and overloading operators - thenew moston

【问题讨论】:

这不是对您的问题或您的链接的批评。而是一个随机的想法,为什么人们会费心制作一个教程 video,有各种各样的干扰(语音、节奏、选择的环境),而不是基于文本的教程(也可以很容易编辑和更新以包含更多信息)。当我点击链接,看到“视频”并立即关闭标签时,我突然冒出一个想法,因为我懒得坐下来看完这一切。不理我。 ;-) @DevSolar:你觉得这很奇怪——上周,有人在 Stack Overflow 上提出了一个问题并得到了澄清请求通过制作视频来回应!跨度> @nwp 在一个写得很好的教程中你也可以得到它,而且它可能比在视频中更容易理解。一个好的老师应该能够像通过视频讲座一样轻松地使用文本进行交流 Sinking:有关视频,请参阅过去几年的 Going Native 会议,为较新的编译器解释新的新技术。这包括很多由于 移动语义 从 C++11 开始可用。 认真的吗?考虑到一次只使用一个隐式转换,这会抹黑所有给定的答案?!曾经我以为我明白了..... 【参考方案1】:

您还需要了解您使用的是复制初始化,而不是直接初始化

They are different,您需要了解如何以及它们与explicit 的关系。您需要了解chains of conversions work 的原理,最多涉及一次用户定义的转换。

Dog d1 ("rover");
Dog d2 = "rover";

d2 案例尝试将文字转换为 Dog,然后将其复制(移动)到 d2。但这将是一个双重转换:const char*string,然后 stringDog

d1 case 构造 d1 将参数传递给构造函数,所以只有一次转换 const char*string。 (在这两种情况下,将const char [6] 升级为const char* 也可以,但不计入允许的“唯一一个”,属于不同的类别。)

复制初始化将“rover”指定为构造函数的参数。它说“这里有东西,但这里需要Dog”。 here 是 copy-init 声明语法的右侧,而不是任何可识别的函数。编译器必须找到合法的转换。

在直接初始化的情况下,您只是为函数(构造函数)提供参数。编译器将您提供的内容转换为声明的参数类型。

【讨论】:

这确实应该被接受为完整的答案。 其他答案也解释了非传递转换流程。但是,我需要先了解整个 copy initialization 的内容,才能将您的答案识别为上级。一旦我支持这一切,我就会回来考虑更改接受的标记。 这是一个非常有条理的解释,赞 快速:我相信 d1 在您编写的课程中可以使用。添加一个 char* 构造函数不是很好。 允许编译器优化出副本!即便如此,它必须检查可用性和调用它的能力。将复制 ctor 设为私有,你会得到一个错误。【参考方案2】:

注意"rover"不是std::string,它是const char[6](末尾有空字符)(可能衰减为const char*),要使Dog d = "rover";工作,"rover"需要转换为std::string,然后转换为Dog

但是user-defined conversion 在一次隐式转换中不会被考虑两次。

(强调我的)

在隐式转换的第二阶段调用自定义转换函数,由零个或一个转换构造函数或零个或一个自定义转换函数组成。

您可以显式"rover" 转换为std::string 以使其工作。

Dog d = std::string("rover");

【讨论】:

可以,但你根本不会写那个。你会写Dog d ("rover");【参考方案3】:

您需要另一个允许您从const char* 构造的构造函数:

Dog(const char* n):name(n)

请记住,"rover" 不是std::string,并且类型不会被推断为隐式使用转换构造函数。正如@songyuanyao 在他们的回答中提到的那样,转换只会进行一次。

另一种选择是写:

Dog d = std::string("rover");

【讨论】:

这个答案会更好,不过,如果它还解释了为什么不能在 OP 的上下文中使用从 const char*std::string 的转换。 但是"rover" 也不是const char*。那么为什么这会解决问题呢?或者为什么首先会出现问题? 我发现我的问题不是缺乏理解如何使用转换构造函数,而是字符串或字符指针的处理方式不同。 另一种选择是使用"rover"s 添加该构造函数并不好,因为该类无论如何都需要一个字符串。您不希望每个接受字符串参数的类都具有另一种形式,尤其是在有多个字符串参数的情况下!您可以从字符串文字初始化 Dog,使用直接初始化。我认为这个答案不是“更好”,而是没有抓住重点。

以上是关于如何正确使用转换构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 React Hooks 将具有构造函数的类转换为功能组件?

通过隐式转换返回时是不是需要复制构造函数?

编写自定义控件构造函数的正确姿势 - defStyleAttr/defStyleRes

编写自定义控件构造函数的正确姿势 - defStyleAttr/defStyleRes

PyQt4 将转换矩阵作为参数传递给构造函数

selenium pandas 数据框构造函数未正确调用