关于是否让班级成员保持不变,我有一个问题。让我举个例子。
#include <iostream>
class ValueClass
{
int ival;
public:
void set(int i) {ival = i;}
int get() {return ival;}
};
class XXX;
class ABC
{
ValueClass vc;
public:
int getval() const {return vc.get() ;}
friend class XXX;
};
class XXX
{
std::vector<ABC> abclist;
void Invalidate()
{
// Iterates through abclist and modifies ValueClass members.
// e.g. abclist[i].vc.set(i);
}
};
class QWE
{
const ABC & abc;
public:
QWE(const ABC & abc_): abc(abc_) { }
const ABC & getABC() { return abc; }
};
int main()
{
ABC abc;
QWE qwe(abc);
std::cout << qwe.getABC().getval() << "\n"; // Compiler error
}
我的ABC
类包含一个ValueClass实例,它负责为int
值设置getter和setter。 QWE
类也有一个ABC
成员,我需要获得此成员。我被告知将abc
作为非常量返回是一种非常糟糕的做法。但问题来了,我不能在const vc
函数中使用非const int getval()
而我根本无法使它成为const
因为在另一个线程XXX::Invalidate()
中被调用。此函数根据某些传入数据更改ValueClass中的数据
显然我的设计有问题,我不能责怪C ++语言。我该如何解决这个问题?
答案 0 :(得分:3)
在ValueClass中创建get()const
class ValueClass
{
int ival;
public:
void set(int i) {ival = i;}
int get() const {return ival;} // make get const
};
可能应该为getABC做同样的事情
const ABC & getABC() const { return abc; }
这意味着此方法不会更改调用它的对象。
答案 1 :(得分:1)
正如其他人所说,访问者应该是const限定的。作为一般规则,如果某些可以是const限定的,那么 应该是const限定的(当然有一些例外,例如函数的返回类型)按值返回不应该是const限定的,尽管通常并不重要。)
但是,编写的代码存在另一个问题:它很容易被错误地使用,并且意外地丢失了对象生命周期。考虑您是否在qwe
中声明main()
为:
QWE qwe(ABC());
ABC()
构造一个临时ABC
对象并将其传递给QWE
构造函数。由于构造函数参数abc_
是const ABC&
,因此它将绑定到该临时对象。然后,通过初始化程序abc
将成员引用abc(abc_)
绑定到临时对象。然后构造函数返回。
构造函数返回后,临时ABC
对象被销毁,qwe.abc
是悬空引用:它不再引用对象。
如果一个类要挂在你传递给它的引用上,你应该更喜欢使用指针作为参数类型:这样,你就更清楚你必须关注潜在的生命周期问题。另外,引用类类成员通常比它们的值更糟糕,因为它们使类不可赋值(因为引用本身不可赋值)。
答案 2 :(得分:0)
class ValueClass
{
...
int get() const {return ival;}
};
class QWE
{
...
const ABC & getABC() const { return abc; }
};
您的代码必须始终是const-correct,否则您将始终遇到此问题。