У меня есть класс структуры данных в C ++ с аксессором к некоторому объекту (может быть большим), и у меня есть const и неконстантные методы, использующие этот аксессор, поэтому мне нужно его перегрузить. Я ищу рецензия кода ниже — может быть, есть способ сделать то же самое, что чище?
Насколько я понимаю, есть два способа добиться этого без дублирования кода в методе доступа в следующем случае, метод get (). Я не уверен, есть ли серьезные проблемы с любым из этих двух методов и Я хотел бы получить руководство Вот.
Мне нравится метод А, потому что:
Мне не нравится метод А, потому что:
Мне нравится метод B, потому что:
Мне не нравится метод B, потому что:
Вот (минимальный) пример кода двух случаев.
/**
* summary:
* Two classes with an overloaded method which is
* guaranteed (by contract) not to change any
* internal part of the class. However, there is a
* version of this method that will return a non-const
* reference to an internal object, allowing the user
* to modify it. Don't worry about why I would ever
* want to do this, though if you want a real-world
* example, think about std::vector<>::front()
*
* The difference between A and B can be summarized
* as follows. In both cases, the second method merely
* calls the first, wrapped with the needed
* const_cast's
*
* struct A {
* int& get();
* int get() const;
* };
*
* struct B {
* const int& get() const;
* int& get();
* };
*
**/
struct A
{
int _val;
A() : _val(7) {};
// non-const reference returned here
// by a non-const method
int& get()
{
// maybe lots of calculations that you do not
// wish to be duplicated in the const version
// of this method...
return _val;
}
// const version of get() this time returning
// a copy of the object returned
int get() const
{
// CONST-CAST!!?? SURE.
return const_cast<A*>(this)->get();
}
// example of const method calling the
// overloaded get() method
int deep_get() const
{
// gets a copy and makes
// a copy when returned
// probably optimized away by compiler
return this->get();
}
};
struct B
{
int _val;
B() : _val(7) {};
// const reference returned here
// by a const method
const int& get() const
{
// maybe lots of calculations that you do not
// wish to be duplicated in the non-const
// version of this method...
return _val;
}
// non-const version of get() this time returning
// a copy of the object returned
int& get()
{
// CONST-CAST!? TWO OF THEM!!?? WHY NOT...
return const_cast<int&>(const_cast<const B*>(this)->get());
}
// example of const method calling the
// overloaded get() method
int deep_get() const
{
// gets reference and makes
// a copy when returned
return this->get();
}
};int main()
{
A a;
a.get() = 8; // call non-const method
a.deep_get(); // indirectly call const method
B b;
b.get() = 8; // call non-const method
b.deep_get(); // indirectly call const method
}
Константность функции-члена должна решаться на основе вопроса: используется функция-член в контексте для изменения объекта? (либо член изменяет объект напрямую, либо возвращает ссылку / указатель на внутренние данные, чтобы внешние абоненты могли изменить объект). Если да, сделайте его неконстантным, иначе сделайте его константным.
Компилятор будет правильно выбирать между перегрузками, которые отличаются только константностью. Тем не мение, возвращаемый тип не используется в разрешении перегрузки. Кроме того, возврат по стоимости / по ссылке должен решаться только на основе ожидаемой стоимости и предполагаемого права собственности на то, что вы собираетесь вернуть. К счастью, C ++ 11 облегчает жизнь, предоставляя переместить семантику. Это означает, что вы можете успешно возвращать большие структуры данных по значению. Вернуть по ссылке только в том случае, если указанный объект переживет внешний вызывающий объект.
Мне кажется, что ваш int& get()
должен быть переименован void set(int)
и что вы могли бы разделить int get() const
в помощник вычислений и собственно get()
class C
{
int val_;
public:
void modify() { /* some expensive computation on val_ */ }
int get() const { return val_; }
void set(int v) { val_ = v_; }
};
В качестве альтернативы, если вы хотите сохранить get()
функции, вы могли бы сделать
class D
{
int val_;
public:
void modify() { /* some expensive computation on val_ */ }
int get() const { modify(); return val_; }
int& get() { modify(); return val_; } // no const-cast needed
};
Других решений пока нет …