同一函数的 const 和非 const 版本 - 反模式?
Both const and non-const version of the same function - an anti-pattern?
最近我检查了大量遗留 C++ 代码,发现了一些我以前从未在生产 C++ 代码中见过的东西:
class Foo
{
public:
void Bar()
{
std::cout << "Hello from Bar()!" << std::endl;
}
void Bar() const
{
const_cast<Foo*>(this)->Bar();
}
};
这是一个巨大的反模式吗?我的意思是,该函数要么是 const 要么是非常量,提供两个版本有什么意义?这是某种 'const-correctness cheat',允许调用 const 函数的情况是这样的:
void InvokeBar(const Foo& foo)
{
// oh boy! I really need to invoke a non-const function on a const reference!
foo.Bar();
}
不,不是 总是。
此模式有合法用途。例如,假设您正在编写一个集合,并且用于检索元素的代码相当复杂(例如哈希 table)。您不想复制所有代码,但您也希望您的集合能够用作常量和非常量。
所以,您可以这样做:
struct HashTable {
...
const Value &get(Key key) const {
... complex code for retrieving the key
}
Value &get(Key key) {
return const_cast<Value &>(
static_cast<const HashTable *>(this)->get(key)
);
}
};
在这里,const_cast<>
并不是真的在撒谎。由于您的函数是非 const
,您知道只有当 this
指向的对象也是非常量时才能调用它。因此,抛开 constness 是有效的。
(当然,与这种情况类似,您可以通过丢弃 const
实例的 const
-ness 来调用非 const
方法,但此时它是你的 class 的用户,他已经引入了未定义的行为,因此只要你的 class 被正确使用,你就会被覆盖。)
最近我检查了大量遗留 C++ 代码,发现了一些我以前从未在生产 C++ 代码中见过的东西:
class Foo
{
public:
void Bar()
{
std::cout << "Hello from Bar()!" << std::endl;
}
void Bar() const
{
const_cast<Foo*>(this)->Bar();
}
};
这是一个巨大的反模式吗?我的意思是,该函数要么是 const 要么是非常量,提供两个版本有什么意义?这是某种 'const-correctness cheat',允许调用 const 函数的情况是这样的:
void InvokeBar(const Foo& foo)
{
// oh boy! I really need to invoke a non-const function on a const reference!
foo.Bar();
}
不,不是 总是。
此模式有合法用途。例如,假设您正在编写一个集合,并且用于检索元素的代码相当复杂(例如哈希 table)。您不想复制所有代码,但您也希望您的集合能够用作常量和非常量。
所以,您可以这样做:
struct HashTable {
...
const Value &get(Key key) const {
... complex code for retrieving the key
}
Value &get(Key key) {
return const_cast<Value &>(
static_cast<const HashTable *>(this)->get(key)
);
}
};
在这里,const_cast<>
并不是真的在撒谎。由于您的函数是非 const
,您知道只有当 this
指向的对象也是非常量时才能调用它。因此,抛开 constness 是有效的。
(当然,与这种情况类似,您可以通过丢弃 const
实例的 const
-ness 来调用非 const
方法,但此时它是你的 class 的用户,他已经引入了未定义的行为,因此只要你的 class 被正确使用,你就会被覆盖。)