简体   繁体   English

为什么调用重载的构造函数会导致调用默认构造函数?

[英]Why does calling an overloaded constructor cause a call of the default constructor?

My C++ Programm always calls too more constructors than i intended to. 我的C ++程序总是调用比我想要的更多的构造函数。 It should create an edge, which then automatically creates two nodes by the string-input of the overloaded edge-constructor. 它应该创建一个边缘,然后通过重载的边缘构造函数的字符串输入自动创建两个节点。

But it first calls the default-constructor of the node objects and then the overloaded self-defined constructor. 但是它首先调用节点对象的默认构造函数,然后调用重载的自定义构造函数。 The destructors do not delete the default nodes immediately. 析构函数不会立即删除默认节点。 That causes an error in my program. 那会导致我的程序出错。

The problem is that the program should count the amount of objects and allocate an appropriate ID related to the amount of objects. 问题在于程序应计算对象数量并分配与对象数量相关的适当ID。

Compiler-Output 编译器输出

Default-Constructor
Default-Constructor
Overload-Constructor
ID: 1 numInstances: 2
Destructor
Overload-Constructor
ID: 2 numInstances: 1
Destructor
Edge:  -> Node_0002

Destructor
Destructor
Program ended with exit code: 0

Here is a snippet for you to see the code which most likely causes the error: 这是一个片段,供您查看最有可能导致该错误的代码:

main.cpp main.cpp

int main() {
    Edge e1 = Edge("1", "2");
    std::cout << "Edge: " << e1.toString() << endl;
    return 0;
}

node.hpp node.hpp

double Node::numInstances = 0;
Node::Node()
{
    numInstances++;
    cout << "Default-Constructor" << endl;
    double idNumber = numInstances;
    m_id = setUpIdString(idNumber);
}

Node::Node(string id)
{
    double idNumber = getNumberFromString(id);
    cout << "Overload-Constructor" << endl;
    cout << "ID: " << idNumber << " numInstances: " << numInstances << endl;
    if (idNumber > numInstances) {
        numInstances++;
        m_id = setUpIdString(idNumber);
    }
}

Node::~Node()
{
    numInstances--;
    cout << "Destructor" << endl;
}

edge.cpp edge.cpp

Edge::Edge(string src, string dst)
{
    m_srcNode = Node(src);
    m_dstNode = Node(dst);
}

EDIT: 编辑:

node.hpp node.hpp

class Node
{
public:
    Node();
    Node(string id);
    ~Node();
    string getId();

private:
    string m_id;
    static double numInstances;
};

edge.hpp edge.hpp

class Edge
{
public:
    Edge(Node& rSrc, Node& rDst);
    Edge(string src, string dst);
    string toString();
    Node& getSrcNode();
    Node& getDstNode();

private:
    Node m_srcNode;
    Node m_dstNode;
};

A constructor is not like other functions in C++. 构造函数与C ++中的其他函数不同。 A constructor's job is to initialize an object. 构造函数的工作是初始化一个对象。 In order to ensure the object gets initialized in a sensible way, all of the member objects (and base objects) need to be initialized. 为了确保以合理的方式初始化对象,需要初始化所有成员对象(和基础对象)。 *This happens before the opening brace of the constructor body, so that everything is in a sensible state when you're in the constructor body. *这发生构造函数主体的大括号之前 ,因此当您在构造函数主体中时,一切都处于明智的状态。

To make sure this happens in the way you want, you can use an initializer list (note that this term also refers to something else when initializing various containers; if you've heard the term before in relation to that, it's not what I'm discussing here). 为了确保按照您希望的方式进行操作,可以使用初始化程序列表 (请注意,在初始化各种容器时,该术语还指其他内容;如果您之前听说过与此相关的术语,那不是我所想的)我在这里讨论)。 After the function signature, you put a colon, followed by each member of your class (in the same order they're declared in the class) and how you want to initialize it. 在函数签名之后,放一个冒号,后跟类中的每个成员(按照它们在类中声明的顺序)以及如何初始化它。 For example, if you have the following struct 例如,如果您具有以下struct

struct A {
    int i;
    char c;
    std::string s;
    A();
};

you can declare define your constructor as 您可以声明将构造函数定义为

A::A() : i{17}, c{'q'}, s{"Hello, mrb! Welcome to Stack Overflow"}
{
    // Nothing to do in the body of the constructor
}

That way, an A object's members are initialized to 17 , 'q' , and a greeting before the start of the function , and are not initialized any other way. 这样, A对象的成员在函数开始之前被初始化为17'q'和问候语,而没有其他任何方式被初始化。


Since you do not do this, the compiler instead uses the default constructor for the nodes. 由于不执行此操作,因此编译器将对节点使用默认构造函数。 You then create other nodes inside the constructor body, and assign them to the nodes in your class. 然后,您可以在构造函数主体内创建其他节点,并将它们分配给类中的节点。

m_srcNode = Node(src);
m_dstNode = Node(dst);

Here, the two objects are first constructed with default constructor, then the overloaded constructed is called with Node(src) and Node(dst) . 在这里,首先使用默认构造函数构造这两个对象,然后使用Node(src)Node(dst)调用重载的构造函数。 After that, the implicitly defined copy assigner is called to assign the temporary objects to m_srcNode and m_dstNode . 之后,将调用隐式定义的副本分配器 ,以将临时对象分配给m_srcNodem_dstNode Finally the temporary objects are destroyed. 最后,临时对象被销毁。

If you want to avoid extra constructor calls, you can write a member initializer list : 如果要避免额外的构造函数调用,可以编写成员初始化器列表

Edge::Edge(string src, string dst) : m_srcNode(src), m_dstNode(dst) {}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM