Имеет ли смысл предоставлять неконстантный эталонный геттер - PullRequest
7 голосов
/ 06 ноября 2010

Иногда мне нужно разоблачить некоторых учеников.Например, в следующем примере class Mechanic может потребоваться прямой доступ к компоненту Engine.Я много раз читал, что все поля должны быть доступны для методов мутатора (аксессора) по нескольким причинам.Но есть ли преимущество при предоставлении неконстантного эталонного геттера:

class Car
{
    public:
        Engine & engine()
        {
           return m_engine;
        }

        //as a consequence you will also need to provide const version
        const Engine & engine() const
        {
           return m_engine;
        }

    private:
       Engine m_engine;
}

по сравнению с простым открытием компонента двигателя:

class Car
{
    public:
        Engine engine;
}

Вы также можете заменить public на protected, есливам не нравится этот пример.В реальной жизни у вас есть что-то похожее на Java, когда дело доходит до System.in или System.out.Похоже, что для полного соответствия тому, что говорят некоторые люди, вам нужно будет выполнять вызовы типа System.getInstance().getOut().println("hello world").Я не вижу никакой выгоды, кроме большого бюрократического кода в таких случаях.

Ответы [ 9 ]

3 голосов
/ 06 ноября 2010

Явные методы получения и установки могут быть чрезмерно бюрократическими;это зависит от вашей ситуации.

Основная причина использования функций getter и setter заключается в том, что она изолирует клиентов вашего класса от возможных изменений в реализации в будущем (например, подумайте, что произойдет, если вы решитесоздать объект Engine по требованию (а не с помощью переменной-члена) или решить скрыть его за умным указателем или каким-либо другим контейнером).

Если ваш класс очень простой (например, близко кбудучи POD ) и вряд ли изменится, то, возможно, не стоит того, чтобы реализовывать методы получения и установки.

Однако, чтобы ответить на ваш вопрос, не-const getter, вероятно, не имеет особого смысла.Ваш прототип геттера должен быть Engine & engine() const;иначе вы не сможете вызвать его на const Car объектах.

3 голосов
/ 06 ноября 2010

Они могут быть полезны, когда возвращаемое вами значение фактически находится в куче.

template<class T> class Singleton
{
private:
    static T* m_pSingleton;

public:
    T& getSingleton() { assert(m_pSingleton); return(*m_pSingleton); };

}; // eo class Singleton
1 голос
/ 13 ноября 2010

Я нашел разумное основание для предоставления такого геттера. Это облегчает интеграцию вашего программного обеспечения (например, когда вы хотите перевести интерфейс на другой язык и связать ABI).

1 голос
/ 06 ноября 2010

Как я недавно узнал, геттеры и сеттеры пахнут плохим дизайном. Но если вы хотите, чтобы это было так, предоставление функций для получения и установки m_engine (определено вами), а не просто его выставление (у вас нет вмешательства) означает, что у вас есть точка подключения для будущих изменений.

1 голос
/ 06 ноября 2010

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

0 голосов
/ 14 ноября 2012

В этом случае вам скорее понадобится функция Car.fix(const Mechanic&), которая затем дает двигателю значение Mechanic, скажем: Engine.fix(const Mechanic&), так как я предполагаю, что состояние Engine будет изменено.

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

Вы хотите только предоставить новые данные, которые класс создает . Скажите Car.get_exhaust(), а Car не имеет выхлопа, а только производит его, когда вы об этом попросите. ;)

Или Fire Riefle.fire(), в то время как механик не установит доступ к Riefle::Trigger следующим образом: Trigger.fix_by(Mechanic), и тогда fix_by позвонит скажем Mechanic.add_working_hour(0.5). XD

0 голосов
/ 06 ноября 2010

да, это имеет смысл - для удобства сопровождения, проверки и согласованности.

вам может понадобиться изменить многие аспекты класса в будущем, предоставив средство доступа, которое поможет минимизировать повреждение клиентского кода.

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

наконец, ваш код будет согласован: вы выиграли 'чтобы узнать видимость члена, нужно открыть заголовок - вы всегда знаете об этом.это также полезно с шаблонами.

0 голосов
/ 06 ноября 2010

Вместо того, чтобы думать о разоблачении частных членов класса, следует больше думать о том, как вызывать методы этих классов.Я прочитал интересную статью по Java, Почему методы Getter и Setter являются злыми , которые относятся к C ++ так же, как и к Java.

0 голосов
/ 06 ноября 2010

Для меня это имеет смысл здесь:

image(i,j) = 234;
...