为什么在构造函数中不允许访问成员对象的成员?
Why is accessing the members of a member object not allowed in a ctor?
class 边缘:
class Edge {
int dist = 0;
std::pair<Node, Node> ends;
public:
Edge() = default;
explicit Edge(const int idist) : dist(idist) { }
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist) {
ends.first = end1;
ends.second = end2;
}
~Edge() = default;
};
在构造函数explicit Edge(const int idist, Node& end1, Node& end2)
中,为什么不允许我使用语法?:
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist), ends.first(end1), ends.second(end2) { }
这是不允许的。作为member initializer list,
的语法
class-or-identifier ( expression-list(optional) ) (1)
class-or-identifier brace-init-list (2) (since C++11)
虽然 ends.first
和 ends.second
不引用 class 或标识符,但它们是表达式。您必须整体初始化 ends
,例如
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist), ends(end1, end2) { }
您尝试做的事情是允许的,但您做事的方式是不允许的。
初始化程序列表指定如何将包含未初始化字节的随机内存位转换为有效对象。然后构造函数可以用这个新对象做一些事情,但是对象状态需要事先初始化。对于默认初始化产生的周围未初始化值有一些注意事项,但在初始化列表中唯一有效的事情是调用成员的构造函数。 (See here 更多关于默认初始化的信息。)
在您的例子中,first
和 second
是 pair
的字段。在构建该对之前,您无法访问它们。即便如此,您也不一定 re-initialize 他们会像您尝试的那样。
解决方案是使用其构造函数之一立即初始化整个对:
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist), ends(end1, end2) { }
C++ 的基本特征之一 类 是每个对象(没有恶意)都将由其构造函数 正确创建 。反过来看,如果一个类型有一个构造函数,那么你必须用构造函数创建那个类型的对象。
在 Edge
的构造函数初始化列表中,构造了 Edge
的每个成员。由于 std::pair
有自己的构造函数,构造一个 Edge
对象意味着用 std::pair
.
的适当构造函数构造 ends
成员
这不是您应该试图绕过的东西。它是声音编程的基础。构造函数创建对象。做你自己的事情有可能创造出没有被正确创造出来的东西。是的,在这种特殊情况下,您可能可以侥幸逃脱。但是绕过构造函数没有任何好处,在其他情况下,这会导致严重的问题。不要绕过构造函数。让他们做他们的工作,这样你的工作就会轻松很多。
class 边缘:
class Edge {
int dist = 0;
std::pair<Node, Node> ends;
public:
Edge() = default;
explicit Edge(const int idist) : dist(idist) { }
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist) {
ends.first = end1;
ends.second = end2;
}
~Edge() = default;
};
在构造函数explicit Edge(const int idist, Node& end1, Node& end2)
中,为什么不允许我使用语法?:
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist), ends.first(end1), ends.second(end2) { }
这是不允许的。作为member initializer list,
的语法class-or-identifier ( expression-list(optional) ) (1) class-or-identifier brace-init-list (2) (since C++11)
虽然 ends.first
和 ends.second
不引用 class 或标识符,但它们是表达式。您必须整体初始化 ends
,例如
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist), ends(end1, end2) { }
您尝试做的事情是允许的,但您做事的方式是不允许的。
初始化程序列表指定如何将包含未初始化字节的随机内存位转换为有效对象。然后构造函数可以用这个新对象做一些事情,但是对象状态需要事先初始化。对于默认初始化产生的周围未初始化值有一些注意事项,但在初始化列表中唯一有效的事情是调用成员的构造函数。 (See here 更多关于默认初始化的信息。)
在您的例子中,first
和 second
是 pair
的字段。在构建该对之前,您无法访问它们。即便如此,您也不一定 re-initialize 他们会像您尝试的那样。
解决方案是使用其构造函数之一立即初始化整个对:
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist), ends(end1, end2) { }
C++ 的基本特征之一 类 是每个对象(没有恶意)都将由其构造函数 正确创建 。反过来看,如果一个类型有一个构造函数,那么你必须用构造函数创建那个类型的对象。
在 Edge
的构造函数初始化列表中,构造了 Edge
的每个成员。由于 std::pair
有自己的构造函数,构造一个 Edge
对象意味着用 std::pair
.
ends
成员
这不是您应该试图绕过的东西。它是声音编程的基础。构造函数创建对象。做你自己的事情有可能创造出没有被正确创造出来的东西。是的,在这种特殊情况下,您可能可以侥幸逃脱。但是绕过构造函数没有任何好处,在其他情况下,这会导致严重的问题。不要绕过构造函数。让他们做他们的工作,这样你的工作就会轻松很多。