为什么当我分配该类的两个对象时,我的构造函数被调用?

问题描述:

我很困惑,如果这很明显,我很抱歉。我错了,在以下内容:为什么当我分配该类的两个对象时,我的构造函数被调用?

struct MyStruct 
    { 
     MyStruct(){}; 
     MyStruct(MyStruct* arg){}; 
    } 

MyStruct(MyStruct * arg){};是一个构造函数将一个指针指向一个MyStruct作为参数?

因为我有一个问题,当我这样做此构造函数(我认为这是)被称为:

int main() 
{ 
    MyStruct obj; 
    MyStruct* objPtr; 
    obj = objPtr; 

    return 0; 
} 

何时objPtr分配OBJ我预计编译器抱怨,但它不” t,而是调用MyStruct(MyStruct * arg);我认为这是一个带指针参数的构造函数。

任何帮助,将不胜感激。另外,如果我向该类添加复制赋值运算符,它仍然会发生。

编辑:谢谢你的答案。它看起来像我有一些阅读要做到这一点,这个话题似乎(任何人想知道)在C++中转换构造函数。另外我猜猜明确的关键字。下面是一个SO问题一个链接,解释它:

What is a converting constructor in C++ ? What is it for?

  1. 编译器合成一个赋值操作符为您提供:

    MyStruct& MyStruct::operator=(MyStruct const&) = default; 
    
  2. 当它看到的分配,它找到一个运营商的候选人(这是它创建的)。然后它会看到它可以使用您的构造函数进行转换,转换为允许赋值的类型(MyStruct)。所以它归结为:

    obj = MyStruct (objPtr); 
    

如果你想看到的错误发生,标记你构造函数明确:

struct MyStruct 
{ 
    MyStruct(){}; 
    explicit MyStruct(MyStruct* arg){}; 
} 
+0

也许注释,如果非默认构造函数是'显式的',这不会发生。 - 哦!你刚刚做到了! –

+1

@MartinBonner,你的意思是我刚添加的那个? – StoryTeller

+0

这很混乱。因此,编译器认为赋值运算符接受一个MyStruct的引用,并且它看到一个指针,而不是说它是不匹配,而是在等号后面用指针作为构造函数的参数构造一个新对象。这很混乱。这是正常的吗?我有权混淆吗?这个东西有一个特殊的名字,所以我可以查看它?哇。谢谢。 – Zebrafish

对于obj = objPtr;时,编译器将尝试调用MyStruct::operator=()obj与参数objPtr,这是MyStruct*。有一个候选人,隐式声明的复制赋值运算符MyStruct::operator=(const MyStruct&)MyStruct可以通过转换器构造函数MyStruct::MyStruct(MyStruct*)MyStruct*转换,所以它编译。

如果你制作MyStruct::MyStruct(MyStruct*)explicit,编译将失败。

struct MyStruct 
{ 
    MyStruct(){}; 
    explicit MyStruct(MyStruct* arg){}; 
}; 

当你sasign objPtrobj,你要指定MyStruct*类型的值MyStruct - 这是无效的。但是,由于您的构造函数需要MyStruct*,因此调用它来转换该值。它基本上是一个隐式转换:)

+0

谢谢。我认为它的要点。我的理解是,它看到赋值运算符接受对结构的引用,并且当它看到指向结构的指针时,它会创建该结构的全新对象,将指针传递给构造函数并将其放在等号后面。我对此很困惑。当你说它调用单指针参数构造函数来“转换”这个值的时候,将指针解除引用来“转换”它会更有意义吗?我的意思是,创建一个你没有指定的全新对象似乎很违反直觉。 – Zebrafish

+0

@TitoneMaurice不完全。在左边,你有一个'MyStruct' - 不是引用,只是一个值。在右边,你有'MyStruct *'。 'MyStruct *'不是*'MyStruct'。如果你没有构造函数,你可以做一些像'obj = * objPtr'(这当然会导致你的示例中的未定义行为)。指向A的指针不是A,它是一个指针。您提供了一个隐式转换运算符,因此编译器使用它。这就是隐式转换操作符的用途。如果你没有提供它,你会得到一个编译器错误 - 再次,你试图分配一个指向*不同类型*的指针。 – Luaan

obj = objPtr; 

会打电话的

obj.MyStruct::operator =(MyStruct(objPtr)); 

标记您的构造explicit避免这类不必要的转换。

+0

你有没有这样的例子,使行为看起来有帮助?我很好奇语言开发人员在想什么。 –

+0

@TheNate听起来很像我典型的OOP。如果有一个采用A并返回B的默认方法,并且您有一个A的实例并且需要一个B的实例,则会调用默认方法。仅仅因为C++(以及大多数其他语言)调用默认方法,构造函数并没有特别说明。这并不像C++的设计者必须做出有意识的决定 - 这是SmallTalk中的一个标准,并且C++受SmallTalk的影响不小。 ML语言今天也使用它(例如F#的'None'作为'Option None'的快捷键)。 – Luaan