Добираются и функции множества, популярные у программистов на C++?

Вы можете использовать flex-direction: column. Это будет складывать гибкие элементы вертикально (сверху вниз)

#wrapper {
  width: 100%;
  height: 400px;
  border: 1px solid black;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

button {
  height: 20px;
  width: 100px;
}
<div id="wrapper">
  <button type="button">hello</button>
  <button type="button">hello</button>
</div>

34
задан Community 23 May 2017 в 12:18
поделиться

13 ответов

Я бы сказал, что предоставление средств доступа более важно в C ++, чем в C #.

C ++ не имеет встроенной поддержки свойств. В C # вы можете изменить открытое поле на свойство в основном без изменения кода пользователя. В C ++ это сложнее .

Для меньшего набора текста вы можете реализовать тривиальные сеттеры / геттеры как встроенные методы:

class Foo
{
public:
    const std::string& bar() const { return _bar; } 
    void bar(const std::string& bar) { _bar = bar; } 
private:
    std::string _bar;
};

И не забывайте, что геттеры и сеттеры несколько злы.

35
ответ дан 27 November 2019 в 16:08
поделиться

Получение и настройка элементов данных как членов данных: Плохо .
Получение и настройка элементов абстракции: Хорошо .

3
ответ дан 27 November 2019 в 16:08
поделиться

Компилятор выдаст set_ и get_, если вы определите свойство, поэтому на самом деле просто сохраните некоторую типизацию.

Это было интересное обсуждение. Это что-то из моей любимой книги "CLR via C #".

Вот что я цитировал.

Лично мне не нравятся свойства и я бы хотел чтобы их не было поддерживается в Microsoftm.NET Фреймворк и его программирование языки. Причина в том, что свойства выглядят как поля, но они методы. Это было известно вызвать феноменальное количество спутанность сознания. Когда программист видит код, который, кажется, обращается к поле, есть много предположений что программист делает то, что может не быть правдой для собственности. Для например,

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

  • Свойство не может быть передано как параметр out или ref параметру Способ; поле может.

  • Метод свойства может занять много времени для выполнения; доступ к полю всегда
    завершает сразу. Общее
    причина использовать свойства
    выполнить синхронизацию потоков, которая может остановить поток навсегда, и
    следовательно, свойство не должно быть
    используется, если синхронизация потоков
    обязательный. В этой ситуации метод является предпочтительным. Кроме того, если ваш класс может быть доступным удаленно (например,
    ваш класс является производным от
    System.MashalByRefObject), вызов
    метод свойства будет очень
    медленный, и, следовательно, метод
    предпочел недвижимость. В моем
    мнение, классы, полученные из
    MarshalByRefObject никогда не должен использовать
    Свойства.

  • Если вызывается несколько раз подряд, метод свойства может вернуть
    разные значения каждый раз; а
    поле возвращает одно и то же значение каждый
    время. Класс System.DateTime имеет Только для чтения Теперь свойство, которое возвращает
    текущая дата и время. Каждый раз Вы запросите это свойство, оно будет
    вернуть другое значение. Это
    ошибка, и Microsoft желает, чтобы
    они могли бы исправить класс, сделав
    Теперь метод вместо свойства.

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

  • Метод свойства может потребовать дополнительной памяти или вернуть
    ссылка на то, чего нет
    на самом деле часть состояния объекта, поэтому изменение возвращаемого объекта имеет
    не влияет на исходный объект;
    запрос поля всегда возвращает
    ссылка на объект, который является
    гарантированно будет частью оригинала состояние объекта. Работа с
    Свойство, которое возвращает копию, может быть
    очень запутанно для разработчиков, и
    эта характеристика часто не задокументировано.
-3
ответ дан 27 November 2019 в 16:08
поделиться

Да, get и set популярны в мире c ++.

-1
ответ дан 27 November 2019 в 16:08
поделиться

Если вы используете C ++ / CLI в качестве вашего варианта C ++, то у него есть поддержка нативных свойств в языке, поэтому вы можете использовать

property String^ Name;

Это то же самое, что и

String Name{get;set;}

в C #. Если вам нужно более точное управление методами get / set, вы можете использовать

property String^ Name
{
   String^ get();
   void set(String^ newName);
}

в заголовке и

String^ ClassName::Name::get()
{
   return m_name;
}

void ClassName::Name::set(String^ newName)
{
   m_name = newName;
}

в файле .cpp. Я не могу вспомнить, но думаю, что у вас могут быть разные права доступа для методов get и set (public / private и т. Д.).

Colin

0
ответ дан 27 November 2019 в 16:08
поделиться

Аргументы против Get / Set с точки зрения дизайна API в примере с банками очевидны. Не открывайте поля или свойства, если они позволят пользователям нарушать ваши бизнес-правила.

Однако, как только вы решили, что вам нужно поле или свойство, всегда используйте свойство.

Автоматические свойства в c # очень просты использовать, и есть много сценариев (привязка данных, сериализация и т. д.), которые не работают с полями, но требуют свойств.

3
ответ дан 27 November 2019 в 16:08
поделиться

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

Eiffel намного лучше где все, что отличается, - это объем информации, который вы должны предоставить, чтобы получить ответ - функция с 0 параметрами равна доступу к переменной-члену, и вы можете свободно переключаться между ними.

Когда вы контролируете обе стороны интерфейса, определение интерфейса не кажется такой большой проблемой. Однако, когда вы хотите изменить детали реализации, и это вызывает перекомпиляцию клиентского кода, как это часто бывает в C ++, вы хотите максимально уменьшить это. Таким образом, pImpl и get / set будут больше использоваться в публичных API, чтобы избежать такого ущерба.

1
ответ дан 27 November 2019 в 16:08
поделиться

Если вы разрабатываете компоненты COM, тогда да, это очень популярно.

1
ответ дан 27 November 2019 в 16:08
поделиться

[ edit] Кажется, мне нужно подчеркнуть, что сеттеры должны проверять параметры и применять инварианты, поэтому они обычно не так просты, как здесь. [/ edit]


Не со всеми, потому что для лишней печати. Теперь я использую их гораздо чаще, когда Visual Assist дает мне «инкапсулированное поле». Да, геттер должен быть постоянным. Однако возвращать значение const бесполезно, если вы возвращаете значение. Для потенциально сложных возвращаемых значений вы, возможно, захотите использовать const, хотя:

std::string const & GetBar() const { return bar; } 

Цепочка установки: Многие разработчики любят изменять установщик следующим образом:

Foo & SetBar(std::string const & bar) { this->bar = bar; return *this; }

, который позволяет вызывать несколько сеттеров как таковые:

Foo foo;
foo.SetBar("Hello").SetBaz("world!");

Это не универсально тем не менее, принято как хорошая вещь.

__declspec (свойство) : Visual C ++ предоставляет это нестандартное расширение, чтобы вызывающие абоненты могли снова использовать синтаксис свойства. Это немного увеличивает нагрузку на класс, но делает код вызывающего абонента более дружелюбным.


Итак, в заключение, немного больше работы, но несколько решений, которые нужно принять в C ++. Типичный;)

6
ответ дан 27 November 2019 в 16:08
поделиться

Я почти никогда не использую геттеры и сеттеры в своем собственном коде. Ответ Veefu выглядит хорошо для меня.

Если вы настаиваете на том, чтобы иметь геттеры и / или сеттеры, вы можете использовать макросы, чтобы вырезать плиту котла.

#define GETTER(T,member) const T& Get##member() const { return member; }
#define SETTER(T,member) void Set##member(const T & value) { member = value; }

class Foo
{
public:
    GETTER(std::string, bar)
    SETTER(std::string, bar)
private:
    std::string bar;
}
4
ответ дан 27 November 2019 в 16:08
поделиться

На самом деле нет строгого соглашения, как в C # или Java. Многие программисты на C ++ просто сделали бы переменную общедоступной, чтобы избавить себя от проблем.

Как уже говорили другие ответы, вам не нужно часто устанавливать и, в некоторой степени, получать методы.

Но если и когда вы делаете для них нет необходимости печатать больше, чем необходимо:

class Foo
{
public:
    std::string Bar() const { return bar; }
    void Bar(const std::string& bar) { this->bar = bar; }
private:
    std::string bar;
};

Объявление встроенных функций в классе экономит типизацию и подсказывает компилятору, что функции должны быть встроенными. И это не намного больше печатания, чем эквиваленты C #. Стоит отметить, что я удалил префиксы get / set. Вместо этого у нас просто две перегрузки Bar (). Это довольно часто встречается в C ++ (в конце концов, если он не принимает никаких аргументов, мы знаем, что это получатель, а если он принимает аргумент, это установщик. Нам не нужно имя, чтобы сказать нам это), и это экономит немного больше печатать.

6
ответ дан 27 November 2019 в 16:08
поделиться

В вашем примере:

class Foo
{
public:
    const std::string GetBar(); // Should this be const, not sure?

Вы, вероятно, имеете в виду это:

std::string GetBar() const;

Помещение константы в конец означает «Эта функция не изменяет экземпляр Foo, это называется ", так что в некотором смысле он помечает его как чистый метод получения.

Чистые методы получения часто встречаются в C ++. Примером в std :: ostringstream является функция str () . Стандартная библиотека часто следует шаблону использования одного и того же имени функции для пары функций получения / установки - снова пример str .

Что касается того, слишком ли много работы печатать, и оно того стоит - это кажется странным вопросом! Если вам нужно предоставить клиентам доступ к некоторой информации, предоставьте получатель. Если нет, то нет.

11
ответ дан 27 November 2019 в 16:08
поделиться

Рискуя спорить, я вернусь к противоположной точке зрения, с которой я впервые столкнулся, читая «Голубой узор». Это была точка зрения, которая была очень сложной, но имела смысл для меня, если подумать:

Методы получения и установки - зло

Использование методов получения и установки противоположно основам объектно-ориентированного проектирования: абстракция данных и инкапсуляция , Чрезмерное использование методов получения и установки сделает ваш код менее гибким и поддерживаемым в долгосрочной перспективе. В конечном итоге они предоставляют базовую реализацию вашего класса, фиксируя детали реализации в интерфейсе класса.

Представьте, что ваше поле 'std :: string Foo :: bar' должно измениться с std :: string на другой строковый класс, что, скажем, лучше оптимизировано или поддерживает другой набор символов. Вы' Вам нужно будет изменить поле личных данных, метод получения, метод установки и весь клиентский код этого класса, который вызывает эти методы получения и установки.

Вместо того, чтобы проектировать свои классы для «предоставления данных» и «получения данных», их «выполнять операции» или «предоставлять услуги». Спросите себя, почему вы пишете функцию «GetBar». Что вы делаете с этими данными? Возможно, вы отображаете эти данные или выполняете их обработку. Этот процесс лучше раскрывать как метод Foo?

Это не означает, что геттеры и сеттеры не имеют своей цели. В C # я считаю, что фундаментальная причина их использования - это взаимодействие с IDE-дизайном Visual Studio GUI, но если вы пишете их на C ++, вероятно, лучше сделать шаг назад, взглянуть на свой дизайн, и посмотрим, чего-то не хватает.

Я попытаюсь смоделировать пример, чтобы проиллюстрировать.

// A class that represents a user's bank account
class Account {
  private:
    int balance_; // in cents, lets say 
  public:
    const int& GetBalance() { return balance_; }
    void SetBalance(int b) { balance_ = b; }
};

class Deposit {
  private:
    int ammount_;
  public:
    const int& GetAmount() { return ammount_; }
    void SetAmmount(int a) { _balance = a; }
};

void DoStuffWithAccount () {
  Account a;
  // print account balance
  int balance = a.GetBalance();
  std::cout << balance;

  // deposit some money into account
  Deposit d(10000);
  a.SetBalance( a.GetBalance() + d.GetValue());
}

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

  1. Целые числа - ужасная валюта тип данных
  2. Депозит должен быть функцией учетной записи.

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

Итак, давайте пропустим этот код и посмотрим, что мы можем улучшить.

// A class that represents a user's bank account
class Account {
  private:
    float balance_;
  public:
    void Deposit(float b) { balance_ += b; }
    void Withdraw(float w) { balance_ -= w; }
    void DisplayDeposit(std::ostream &o) { o << balance_; }
};

void DoStuffWithAccount () {
  Account a;
  // print account balance
  a.DisplayBalance(std::cout);

  // deposit some money into account
  float depositAmt = 1000.00;
  a.Deposit(depositAmt);
  a.DisplayBalance(std::cout);
}

«Поплавок» - это шаг в правильном направлении. Конечно, вы могли бы изменить внутренний тип на «float» и при этом поддерживать идиому getter / setter:

class Account {
  private:
    // int balance_; // old implementation
    float balance_; 
  public:
    // support the old interface
    const int& GetBalance() { return (int) balance_; }
    void SetBalance(int b) { balance_ = b; }
    // provide a new interface for the float type
    const float& GetBalance() { return balance_; } // not legal! how to expose getter for float as well as int??
    void SetBalance(float b) { balance_ = b; }
};

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

Класс, подобный Account, вероятно, не лучший пример, так как «получение» остатка на счете является естественной операцией для учетной записи. Однако в целом вы должны быть осторожны с геттерами и сеттерами. Не имейте привычку писать геттеры и сеттеры для каждого члена данных. Довольно просто разоблачить и заблокировать себя в реализации, если вы не будете осторожны.

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

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

33
ответ дан 27 November 2019 в 16:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: