在此示例中,为什么P3需要默认构造函数?

发布于 2025-01-23 10:32:18 字数 1529 浏览 1 评论 0原文

假设我有这样的C ++代码:

 //main.cpp

#include "p3.h"
#include "tri3.h"

int main()
{
    p3 point1(0.0f, 0.0f, 0.0f);
    p3 point2(1.0f, 0.0f, 0.0f);
    p3 point3(2.0f, 0.0f, 0.0f);

    tri3 triangle(point1, point2, point3);
}

//p3.h

#pragma once

class p3
{
public:
    float _x;
    float _y;
    float _z;
    p3(float x, float y, float z)
    {
        _x = x;
        _y = y;
        _z = z;
    }
};

//tri3.h

#pragma once

#include "p3.h"

class tri3
{
public:
    p3 _p1;
    p3 _p2;
    p3 _p3;
    tri3(p3 p1, p3 p2, p3 p3)
    {
        _p1 = p1;
        _p2 = p2;
        _p3 = p3;
    }
};

汇编失败,在Visual Studio 2022中出现以下错误:错误C2512:'p3':

当我像这样编辑“ p3.h”时, 没有适当的默认构造函数可用 ,汇编是成功的,没有任何错误:

//p3.h

#pragma once

class p3
{
public:
    float _x;
    float _y;
    float _z;
    p3(float x, float y, float z)
    {
        _x = x;
        _y = y;
        _z = z;
    }

    p3() = default; // <-- Adding this makes the program compile just fine
};

在Microsoft文档中,有关错误c2512 ,有一个没有参数创建的对象的示例,并且由于没有默认构造函数,因此发生了此错误。但是,在此示例中,我通过传递所有必要的参数来创建对象。为什么我仍然需要默认构造函数?

Let's say I have C++ code like this:

 //main.cpp

#include "p3.h"
#include "tri3.h"

int main()
{
    p3 point1(0.0f, 0.0f, 0.0f);
    p3 point2(1.0f, 0.0f, 0.0f);
    p3 point3(2.0f, 0.0f, 0.0f);

    tri3 triangle(point1, point2, point3);
}

//p3.h

#pragma once

class p3
{
public:
    float _x;
    float _y;
    float _z;
    p3(float x, float y, float z)
    {
        _x = x;
        _y = y;
        _z = z;
    }
};

//tri3.h

#pragma once

#include "p3.h"

class tri3
{
public:
    p3 _p1;
    p3 _p2;
    p3 _p3;
    tri3(p3 p1, p3 p2, p3 p3)
    {
        _p1 = p1;
        _p2 = p2;
        _p3 = p3;
    }
};

The compilation fails with the following error in Visual Studio 2022: error C2512: 'p3': no appropriate default constructor available

When I edit "p3.h" like this, the compilation is succesfull with no errors:

//p3.h

#pragma once

class p3
{
public:
    float _x;
    float _y;
    float _z;
    p3(float x, float y, float z)
    {
        _x = x;
        _y = y;
        _z = z;
    }

    p3() = default; // <-- Adding this makes the program compile just fine
};

In the Microsoft documentation about error C2512, there is an example of an object being created with no arguments and because it has no default constructor, this error occurs. However, in this example, I create my objects by passing all necessary arguments. Why do I still need a default constructor?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不必在意 2025-01-30 10:32:18
    tri3(p3 p1, p3 p2, p3 p3)

构造函数无法初始化其类的_P1_P2_p3成员,因此它们必须具有默认的构造函数。

        _p1 = p1;
        _p2 = p2;
        _p3 = p3;

这不是构造。这将分配给 现有 对象。他们已经构造了。

要正确构建类成员,您必须在构造函数声明本身中使用 成员初始化

    tri3(p3 p1, p3 p2, p3 p3) : _p1{p1}, _p2{p2}, _p3{p3}
    {
    }

您必须遵循许多重要的规则,在正确使用成员初始化时,请参阅您的C ++教科书以获取更多信息。

    tri3(p3 p1, p3 p2, p3 p3)

The constructor fails to initialize its class's _p1, _p2, and _p3 members, therefore they must have a default constructor.

        _p1 = p1;
        _p2 = p2;
        _p3 = p3;

This is not construction. This is assigning to existing objects. They are already constructed.

To properly construct class members you must use member initialization in the constructor declaration itself.

    tri3(p3 p1, p3 p2, p3 p3) : _p1{p1}, _p2{p2}, _p3{p3}
    {
    }

There are a number of important rules that you must follow, when it comes to properly using member initialization, see your C++ textbook for more information.

此刻的回忆 2025-01-30 10:32:18

问题是由您的tri3构造函数引起的。

按照您的方式实现它,意味着p3 _p1等应该默认构建,然后分配给(在tri3构造函数的主体中)。

您应该更改以下实现,以避免_p1_p2_p3

tri3(p3 p1, p3 p2, p3 p3)
    :_p1(p1), _p2(p2), _p3(p3)
{}

这被称为成员初始化器列表构造函数和成员初始化器列表

The problem is caused by your tri3 constructor.

Implementing it the way you did, means that p3 _p1 etc are supposed to be default constructed, and then assigned to (in the body of the tri3 constructor).

You should change the implementation like the following to avoid the default construction step for _p1,_p2,_p3:

tri3(p3 p1, p3 p2, p3 p3)
    :_p1(p1), _p2(p2), _p3(p3)
{}

This is called member initializer list: Constructors and member initializer lists

冰之心 2025-01-30 10:32:18

您声明的任何对象都是候选人,其构造函数将被调用。
如果对象具有默认的构造函数,则仅数据类型和对象名称就足够了,则不需要其他任何其他括号之类的东西。否则,您应该仔细设计班级是否需要成员初始化。

编译器主要警告您有关您未正确初始化的变量/对象。

如上所述,您声明的任何对象都需要初始化。编译器将寻找可用的构造函数。如果有完美的合适,将选择它。否则,您将获得不可避免的错误,例如:

错误C2512:'datatype':没有适当的默认构造器可用

此外,尝试通过def> default关键字进行修复。正如我所说,即使编译器未通知您,您将创建的对象也可能需要一些初始化的对象。

一些例子:

class Foo
{
public:
   Foo(){};// This is a default constructor
   // You could use Foo() = default; instead. No difference between them
}
// You can safely create it
Foo foo;// ok
Foo foo(); // ok

但是,如果您有类似的内容:

class Bar
{
public:
    Bar(const std::string& string) : _string("test"),_string_(string) ;// both should be here, you cannot use default constructor for this class. 
//(In addition, as _string("test") suggests, it may have an rvalue but the reference type can't)
    {};
    
private:
   // Both should be in initializer list
   const std::string _string;
   std::string& _string_;
}

这种情况会警告您。
但是,如果您有类似的东西:

class FooBar
{
public:
FooBar(){};
private:
int m_number;// some compilers won't even warn you about this
Bar* p_PointerObject;// or this
}

因此,有时由于某些编译器而似乎有效,但是您的程序会在某个时候崩溃。

Any object you declare is a candidate whose constructor will be called.
If object has default constructor, only data-type and object name is enough, no need anything additional like parentheses. Otherwise, you should carefully design your class whether it requires members initialized.

Mostly compiler warns you about the variables/object that you did not properly initialized.

As I mentioned above, any object you declare will need to be initialized. Compiler will look for the available constructors. If there's a perfect fit, it will be chosen. Otherwise, you'll get an inevitable error like:

error C2512: 'dataType': no appropriate default constructor available

Additionally, trying to fix it by default keyword is not appropriate. As I said, the object you will create may require some objects initialized even if compiler does not notify you.

Some examples:

class Foo
{
public:
   Foo(){};// This is a default constructor
   // You could use Foo() = default; instead. No difference between them
}
// You can safely create it
Foo foo;// ok
Foo foo(); // ok

But if you have something like:

class Bar
{
public:
    Bar(const std::string& string) : _string("test"),_string_(string) ;// both should be here, you cannot use default constructor for this class. 
//(In addition, as _string("test") suggests, it may have an rvalue but the reference type can't)
    {};
    
private:
   // Both should be in initializer list
   const std::string _string;
   std::string& _string_;
}

That was a situation that compiler would warn you about.
But if you would have something like:

class FooBar
{
public:
FooBar(){};
private:
int m_number;// some compilers won't even warn you about this
Bar* p_PointerObject;// or this
}

So, sometimes it may seem to work because of some compilers but your program will crash at a point.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文