2013-07-29 2 views
1

Дано:Возвращает члену класса плохую практику?

Class A 
{ 
    private: 
     double **CR; 
    public: 
     double **compute2D(); 
}; 

Предположим, что у меня есть частный элемент 2D массива:

double **CR; 

И у меня есть функция-член:

Double ** Compute2D() 

Функция computer2D будет возвращать CR.

Это плохая практика? Почему? Должен ли я использовать функции getter и setter, чтобы вернуть его?

И еще один вопрос: правильно ли я использую сборщик мусора?

A::~A() 
{ 
    //Delete 2D array 
    for(int i = 0; i < Rows; ++i) 
    { 
     delete [] CR[i]; 
    } 

    delete [] CR; 
} 
+2

«Я правильно использую сборщик мусора?» - Нет, поскольку нет сборщика мусора. Вы, кажется, правильно удаляете выделенную память, но если вы хотите обходиться с помощью 'new' и' delete', вам нужно будет реализовать или предотвратить копирование в [«Правило трех»] (http: // stackoverflow .com/вопросы/4172722). Еще лучше используйте класс RAII, например 'std :: vector', чтобы управлять памятью для вас (в соответствии с« Правилом нуля »). –

+0

, вы можете захотеть вернуть указатель const, чтобы предотвратить другие классы, изменив частный член. Это можно обойти, используя reinterpret_cast, но это, как правило, также будет считаться плохим стилем. – Laurijssen

ответ

0

Reterning метод класса прекрасно подходит, если вы хотите, чтобы члены класса должны быть видимы вне класса, который полностью зависит от того, что вы пытаетесь достичь. Что касается использования метода геттера, вы уже являетесь; это «хорошая практика», чтобы использовать такие методы для создания более равномерной инкапсулированной установки для вашего класса и, следовательно, упростить редактирование этого класса позже. Даже если ваша функция выполняет другие вещи (в этом случае вычисляет что-то в двух измерениях), это все равно метод getter.

В этом конкретном случае, однако, вы не возвращаете значение; вы возвращаете двойной указатель на значение. Это означает, что пользователь сможет редактировать данные (которые я угадываю - это массив), но это нехорошо. Перед возвратом необходимо выполнить глубокую копию данных.

Что касается правильного использования сборщика мусора: да, вы. Хотя он не называется сборщиком мусора в C++, его просто называют освобождением памяти; сборщик мусора - это название системы, которая автоматически освобождает память.

+0

Ahh yess Я вижу. Благодарю вас за ваш вопрос @quinxorin. Таким образом, даже с функцией возврата геттера внешний пользователь может изменить право? И если я возвращаю указатель const. Это означает, что он не может быть изменен. –

+1

Я не согласен. В общем случае это не очень хорошая идея. Вы действительно думаете, что возвращение чего-то типа 'std :: vector > big_table' - хорошая идея? Это может быть хорошо только для небольших базовых типов, таких как числовые типы. Может, струны, самое большее. – luk32

+0

Возвратите структуру данных по ссылке (const или нет), а затем ее вызывающая сторона решит, хочет ли он ее копию. –

1

Посредством этого вы позволяете изменять значение частного члена вне класса. Это зависит от вас, если это плохо или хорошо. Но, на мой взгляд, если у меня есть частный член, то я должен быть единственным, кто может изменить его ценность.

+0

да я вижу @Ali спасибо. Я думаю, что я должен изменить его. Но даже, как я сказал Quinxorin, если я использую функцию геттера, пользователь может изменить свои значения. –

1

Плохо возвращать указатель на частный член вашего класса, потому что он может разрушить инкапсуляцию. Кто-то сможет изменить значение частной переменной без
сообщите об этом вашему классу. Однако нет ничего плохого в обратном копировании полей вашего класса. При использовании getter и setter невозможно изменить состояние класса без знания класса. Так что это хорошая практика.

С удалением массива все выглядит нормально.

1

Если вы верните указатель или не const-ссылку на свой личный член данных через общедоступный метод, бессмысленно сделать его приватным. Вы также можете сделать недвижимость публичной.

В основном это означает, что вы позволяете манипулировать членом вне класса. ИМО это считается плохой практикой, или даже анти-шаблон, потому что класс не может зависеть от своего собственного состояния. Это очень важно.

E.g: Представьте, что у вас есть указатель, и кто-то устанавливает его на null. Даже частные методы должны были бы проверить его, даже если внутренне такое состояние невозможно достичь.

Возвращающиеся нормальные члены, такие как классы считается плохой практикой , потому что она включает в себя копирование целых объектов. Обычно лучше возвращать ссылку или, вероятно, предпочтительно константу ссылки.

Получатели, в свою очередь, позволят вам установить ограничения const. В обоих случаях указатели и ссылки.

Также обратите внимание, что в таких случаях обычно предусмотрено два метода. compute и get. В настоящее время вы можете получить доступ к своему члену, только вычислив его!

Я не зашел так далеко, чтобы предложить вам перейти на std::vector, так как я не знаю, что вам нужно, и векторы не хороши для всего. Так наклеивание с указателями, это безопасный путь:

class A 
{ 
    private: 
     double **CR; 
    public: 
     double const * const * compute2D(); 
     double const * const * getCR(); 
}; 

double const * const * A::compute2D(){ 
return CR; 
} 

double const * const * A::compute2D(){ 
/*Heave CPU stuff*/ 
return CR; 
} 

int main(){ 
A a; 
double const* const* tmp = a.compute2D(); 
tmp[1][2] = 0; //this will fail to compile 
tmp[1] = 0; //this will fail too 

double get_test = tmp[1][2]; // this passes! 
} 

Примечания двойных const классификаторов. Важно защитить каждый уровень ссылок указателей.

1

Возвращение члена класса в порядке. Однако в вашем случае я бы сделал это несколько иначе. Вы возвращаете указатели на 2D-вектор. Таким образом, вы можете вернуть результат своих расчетов, вам не нужно делать копию данных. И поскольку он возвращает значение const, вы уверены, что вызывающий абонент не сможет изменить данные, но может использовать его для чтения значений.

Class B 
{ 
    private: 
     vector<vector<double> > CR; /*note space between > > is significant*/ 
    public: 
     const vector<vector<double> >& compute2D(){ 
      /*do calculation here eg.*/ 
      return CR; 
     } 
}; 

И так как мой пример показать это, как вы можете сделать это с помощью std::vector вы не должны wory об удалении динамически зарезервированный памяти. Вы должны убедиться, что экземпляр Class B не уничтожается, например, выйдя из области действия, если вы все еще используете ссылочную переменную.

+0

AFAIK, это было важно из-за неоднозначных/багги правил синтаксического анализа. Я не помню, чтобы стандарт был недостаточно точным или просто gcc-багги, так как я помню, что компилятор Visual Studio отлично работал. Однако, лучше безопасно, чем жаль! – luk32

+0

@ luk32 gcc все еще анализирует его как оператор '>>', если пробел опущен. myversion of g ++ говорит 'error: '>>' должен быть '>>' в списке вложенных аргументов шаблона', если я его не использую. (Хотя не при компиляции с -std = C++ 0x), но для меня ;-) – hetepeperfan

+0

О, C++ 0x is passe! Мы находимся в 'C++ 11'! Btw. Я думаю, что это была стандартная «ошибка», если изменение режима изменяет семантику. – luk32

1
  1. это плохо, потому что вы возвращаетесь приватную переменную с записью доступа, может быть, это не так, частный
  2. это плохо bacause вы возвращаете указатель, в этом случае не ясно, кто несет ответственность за освободите память: класс, потому что это его собственный член или пользователь, так как он вызывает метод?
+0

да, я вижу, я думаю, что я думаю, что Java и C# не C++. Будьте осторожны в этом. –

+0

для 1. те же правила применяются для каждого языка OO с частным/общедоступным охватом –