C++ 构造函数指针更改
我有一个文件C++ 构造函数指针更改,c++,C++,我有一个文件test.cpp: #include <stdio.h> class B { public: B() {} }; class A { public: A(B *b) { b = b; } B *b; }; int main() { B b = B(); A a = A(&b); printf
test.cpp
:
#include <stdio.h>
class B {
public:
B() {}
};
class A {
public:
A(B *b) {
b = b;
}
B *b;
};
int main() {
B b = B();
A a = A(&b);
printf("b: %p\n", &b);
printf("a.b: %p\n", a.b);
}
我假设指针是直接为构造函数复制的,但是我们看到B
类的A
实例中保存的值发生了变化
任何帮助都将不胜感激
编辑——关于这个问题可能离题的讨论:
我不认为这是一个“简单的印刷错误”,因为在这种情况下,名称范围错误并不明显
- 这是一个在隔离环境中创建的程序,旨在演示错误
- 例如,在Python中,这样的类变量赋值方法是允许的。虽然这种命名方案的优点可以留待讨论,但这里有一个合理的混乱基础
- 我也在寻找这个问题的解决方案(承认很幼稚),而且在网上也很难找到解决方案
编辑——很明显,这个问题已经得到了彻底的回答,因此不需要进一步的回答。然而,如前所述,关闭“主题外”的原因仍有争议。将A的构造函数更改为
A(B *b) : b(b) {}
在
b=b
中,b
的两个出现都涉及构造函数参数。该成员未初始化
解决方案:
- 使用初始化列表,
A(B*B):B(B){}
- 重命名参数,使其不隐藏成员
- 将成员称为
this->b
- 将
A::A()重写为
A(B *b) {
this->b = b;
}
否则,b=b中的b
s代码>引用相同的变量:参数。在我写这篇文章时,答案已经被选为“解决方案”
问题是,自我分配b=b
,源于对两个不同的事物使用相同的名称b
,从而混淆了这两个含义
selected as solution答案确实包括为不同的事物使用不同名称的可能性,但它将此限制为重命名参数,并建议将proven保持为相同的名称
由于问题直接源于对不同的事物使用相同的名称,因此最直接的解决方案是对不同的事物使用不同的名称
在本例中,实现这一点的最简单方法是删除构造函数,这样就只剩下数据成员了——现在它的名称是唯一的
然后原始代码
class A {
public:
A(B *b) {
b = b;
}
B *b;
};
例如,变得只是
struct A { B* b; };
和原始实例化A(p)
变成A{p}代码>
简单得多
拥有一个构造函数至少意味着类不变量的可能性,在这种情况下,谨慎地限制对数据成员的访问
几乎普遍的惯例是对非
公共
成员变量使用一些前缀或后缀。例如,Microsoft使用m
前缀,而其他许多公司使用下划线后缀。(下划线作为前缀保留给全局命名空间中的实现。)
使用数据成员的下划线后缀约定,并使用更普遍适用的内存初始值设定项替换赋值,原始值如下所示:
class A
{
private:
B* b_;
public:
auto b() const
-> B*
{ return b_; }
A( B* b_value )
: b_( b_value )
{}
};
如果没有类不变量,前面显示的简单的struct
就足够了,而这个更详细、更复杂的代码(或等效代码)是安全维护类不变量所需要的。原始代码介于两者之间。对于简单数据结构的情况来说不够简单,但是对于has不变的情况来说不够安全
重命名参数以便不隐藏成员是有问题的,因为它保持了简单抽象级别和安全抽象级别之间的中间位置。这也是将成员称为this->b
的想法的一个问题。使用初始化器列表<代码> A(b*b):b(b){} //>是有问题的,因为它依赖于语言的微妙性,因此大多数普通C++程序员可能必须至少考虑两次以确保其正确性,因此至少一些人会认为它是错误的。(虽然我会猜到,-Wall
抓住了这一点)。再想一想,没关系。警告这一点的是叮当声。作为旁白,bb;
和aaa(&B);
同样有效,而%p
的printf
的参数应该是void*
(这不会发生在std::cout
上)。语句b=b;
是一种自赋值。对于有效的指针值,它没有任何效果,除了可能使用纳秒或两纳秒。命名不明确的变量的危险:):)可能提到我们建议重命名。@Cheersandhth.-Alf:请自言自语。如果有人需要我的推荐,我会推荐一个初始化列表。重命名该成员以使其不被参数隐藏的好理由包括(1)更清楚名称指的是什么,(2)这是几乎普遍的约定。这并不排除使用初始值设定项列表。我会两者都做。@Cheers-Sandhth.-Alf:(1)它同样清楚,除非构造函数太复杂;(2) 我必须和你生活在不同的世界里。(而且,如果您确实重命名了它,在初始化器列表中会有意外地对其进行自初始化的危险。)谢谢——我想我在Python模式下停留了一秒钟这里=P而且,我忘了我可能还应该使用\u b
来规避这类问题(私有范围,yadda yadda yadda等)。
class A
{
private:
B* b_;
public:
auto b() const
-> B*
{ return b_; }
A( B* b_value )
: b_( b_value )
{}
};