2013-06-05 2 views
1

У меня есть класс структуры данных в C++ с доступом к некоторому объекту (может быть большим), и у меня есть методы const и non-const с использованием этого аксессора, поэтому мне нужно чтобы перегрузить его. Я ищу критика из кода ниже - может быть, есть способ сделать то же самое, что чище?Перегруженные методы const и non-const, возвращающие ссылки в C++

Способ, которым я это понимаю, есть два способа добиться этого, не дублируя код в аксессуре в следующем случае, метод get(). Я не уверен, есть ли серьезные проблемы с любым из этих двух методов и Я хотел бы получить руководство здесь.

Мне нравится метод А потому:

  • только один const_cast
  • Уста-версия метода Get() возвращает копию
  • неконстантного метод получает неконстантную ссылку непосредственно

Мне не нравится метод А потому:

  • неконстантный метод Get() является сопзЬ только по контракту, (не проверяется компилятором)
  • сложнее получить константную-ссылку, хотя и не невозможно

Мне нравится метод B, потому что:

  • сопзЬ-ность константным метода Get() проверяется компилятором
  • копия возвращаемого объекта управляется пользователем

Я не люблю метод B, потому что:

  • требует два const_casts, которые трудно читать

здесь есть (минимальный) пример код из двух случаев.

/** 
* 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 
} 
+1

Если код не имеет никаких проблем (что вы знаете о), то это, вероятно, принадлежит на http://codereview.stackexchange.com/ –

+0

Ах, сделал не знаю, что сайт существует, спасибо! Я просто создал тот же вопрос о codereview. http://codereview.stackexchange.com/questions/27064/overloaded-const-and-non-const-class-methods-returning-references-in-c – Johann

+0

Проголосовало за то, чтобы закрыть здесь, поскольку он был перекрестком, отправленному в обзор кода. http://codereview.stackexchange.com/questions/27064/overloaded-const-and-non-const-class-methods-returning-references-in-c/27161#27161 –

ответ

2

константность функции члена должно быть принято на основе вопроса: функция член используется в контексте, чтобы изменить объект? (либо член изменяет объект напрямую, либо возвращает ссылку/указатель на внутренние данные, чтобы внешние вызывающие лица могли изменять объект). Если да, сделайте его неконстантным, иначе сделайте его const.

Компилятор будет правильно выбирать между перегрузками, которые отличаются только от константы. Однако, тип возврата не используется при разрешении перегрузки. Кроме того, возврат по значению/по ссылке должен определяться только ожидаемой стоимостью и предполагаемым правом собственности на то, что вы собираетесь вернуть. К счастью, C++ 11 облегчает жизнь, предоставляя move semantics. Это означает, что вы можете с радостью вернуть значительную ценность больших структур данных. Возвращайтесь по ссылке только в том случае, если ссылочный объект перейдет в режим внешнего абонента.

Мне кажется, что ваш 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 
}; 
+0

Возможно, мой код был слишком минимальным. Представьте, что get() действительно получает (string), и есть много (потенциально рекурсивных) вычислений, которые выполняются со строкой, чтобы точно определить, какой объект возвратиться. Я хочу вернуть ссылку на объект public (public), но также иметь возможность вызывать один и тот же (или перегруженный) метод из метода const. – Johann

+1

@Johann То же самое: напишите вспомогательную функцию, которая выполняет вычисление, и напишите 2 'get()' функции, чтобы вернуть состояние объекта, которое каждый вызывает внутренний помощник вычисления. – TemplateRex

 Смежные вопросы

  • Нет связанных вопросов^_^