我想问一个关于方法的const-correctness的问题。让我来说明一下情况。
class MyClass
{
public:
...
void DiscussedMethod() { otherClass->NonConstMethod(); }
private:
OtherClass *otherClass;
};
我有一个班级MyClass
,它会指向OtherClass
。在DiscussedMethod
中,它调用OtherClass::NonConstMethod
来修改一些可见数据。
我想知道,制作DiscussedMethod
const
是否是一个好习惯(因为它不会修改任何成员数据)?这会是一种不好的做法吗?或者两者都很好?
如果OtherClass
保留指向MyClass
的指针并且NonConstMethod
修改了某些MyClass
'数据(意味着MyClass
成员数据,该怎么办?会在DiscussedMethod
来电期间发生变化。那么制作DiscussedMethod
const
会不会是一种不好的做法?
据我所知,方法上的const
主要是代码记录的东西,所以我可能倾向于不做DiscussedMethod
{{1} },但我想听听你的意见。
编辑:有些回复会考虑const
指向的对象是否归otherClass
对象所有。在我正在使用的场景中情况并非如此。让我们说两个对象并排存在(能够相互修改)。我认为这个类比很好地描述了我的情况。
例如,考虑像双向链表这样的东西,其中每个元素都是一个保持指向其邻居和成员变量MyClass
的指针的类。它有方法color
,它改变了邻居的MakeNeighboursRed
但不影响调用对象的状态本身。我应该考虑制作这种方法color
吗?
如果const
可能会调用邻居的MakeNeighboursRed
,那该怎么办?因此,最终调用MakeNeighboursRed
的对象的状态也会发生变化。
我要感谢大家的意见: - )
答案 0 :(得分:6)
如果MyClass
拥有OtherClass
个实例,我就不会使DiscussedMethod
保持不变。
类,管理资源也是如此。即标准容器不会使用const函数返回非const引用或指向托管内存的指针,尽管它是“可能的”(因为保存资源的实际指针未被修改)。
考虑
class MyClass
{
public:
bool a() const { return otherClass->SomeMethod(); }
void b() const { otherClass->NonConstMethod(); }
private:
OtherClass *otherClass;
};
void foo (MyClass const &x)
{
cout << boolalpha << x.a() << endl;
x.b(); // possible if b is a const function
cout << boolalpha << x.a() << endl;
}
虽然foo
的实现者可能期望const对象上的两个函数调用具有相同的行为,但foo
可以打印两个不同的值。
澄清:
根据标准,以下内容无效,因为operator[]
的const版本返回std::vector<T>::const_reference
,这是对值类型的常量引用。
std::vector<int> const a = { /* ... */ };
a[0] = 23; // impossible, the content is part of the state of a
如果只有一个这个函数的签名,即referece operator[] (size_t i) const;
,就有可能,因为操作不会改变向量的内部指针,而是改变它们指向的内存。
但是由向量管理的内存被认为是向量状态的一部分,因此通过const向量接口无法进行修改。
如果向量包含指针,那么这些指针仍然可以通过公共const向量接口进行修改,尽管存储在向量中的指针很可能是非常量的,并且很可能改变它们指向的内存。
std::vector<int*> const b = { /* ... */ };
int x(2);
b[0] = &x; // impossible, b is const
*b[0] = x; // possible since value_type is int* not int const *
答案 1 :(得分:4)
在OOP对象中,应该通过其接口提供的状态来完整描述。因此,如果可以通过接口观察到这些变化,则const方法不应该改变对象的状态。
一个很好的例子是类中的mutable
互斥锁来保护一些共享资源。它可能会从const
方法修改,因为它不会通过类接口引入任何可观察到的更改。
答案 2 :(得分:3)
一般的经验法则是,如果你可以使一个成员函数const,你可能应该。这样做的原因是它可以让你更容易地捕捉到意想不到的行为和错误。
另一个有利的论点是,如果你将这个函数作为const,你可以在const对象上调用它,所以它实际上不是文档。
答案 3 :(得分:2)
总的来说,这取决于其他课程。它不是黑白的......
如果otherClass
是一个日志对象(例如),并且您想记录当前对象的操作,那么从const函数调用它就完全没问题。
如果otherClass
是一个容器,设计(或实现)目的是作为一个单独的对象实现而不是有效的const函数修改对象使这个想法非常糟糕。< / p>
我希望这会有所帮助。
答案 4 :(得分:1)
使DiscussedMethod
const
更改为*this
状态完全不正确。唯一的漏洞是使非逻辑 - 对象的状态成员数据mutable
,以便可以在const
函数中进行更改。这就像是一个成员,其中包含“已调用函数x()
的次数”。其他任何东西都是对象的状态的一部分,如果一个函数改变了它(在任何级别),那么该函数不是const
。
答案 5 :(得分:1)
我想知道,制作DiscussedMethod const是否是一个好习惯(因为它不会修改任何成员数据)?
otherClass
是成员数据,它(或更确切地说,它指向的对象)会被修改。
考虑到指向otherClass
的指针应该重构为完全拥有的对象的语义......是否某些东西被保存为指针,引用或对象不会改变语义所有权,IMO。