Недавно я проверил огромное количество унаследованного кода C ++ и нашел то, чего никогда не видел в производственном коде C ++:
class Foo
{
public:
void Bar()
{
std::cout << "Hello from Bar()!" << std::endl;
}
void Bar() const
{
const_cast<Foo*>(this)->Bar();
}
};
Это огромный анти-паттерн? Я имею в виду, что функция является константной или неконстантной, какой смысл предоставлять две версии? Является ли это своего рода «обманом константности», который позволяет вызывать константные функции в таких ситуациях:
void InvokeBar(const Foo& foo)
{
// oh boy! I really need to invoke a non-const function on a const reference!
foo.Bar();
}
Нет не всегда.
Есть законное использование этого шаблона. Например, предположим, что вы пишете коллекцию, а код для извлечения элемента довольно сложный (например, хеш-таблица). Вы не хотите дублировать весь код, но вы также хотите, чтобы ваша коллекция могла использоваться как постоянная, так и неконстантная.
Итак, вы можете сделать что-то вроде этого:
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
также неконстантен. Следовательно, отбрасывание константности действительно.
(конечно, аналогично этой ситуации, вы можете назватьconst
метод, отбрасывая const
-есть const
экземпляр, но в этот момент это пользователь вашего класса, который уже ввел неопределенное поведение, так что вы покрыты, пока ваш класс используется правильно.)
Других решений пока нет …