oop — ссылочное поле Const как свойство только для чтения в классе C ++

Хорошо ли использовать поле ссылки const в качестве метода чтения только для классов C ++?

Я имею в виду, соответствует ли этот код передовой практике?

class check{
private:
int _x;
public:
const int& x = _x;
void setX(int v){
_x = v;
}
};

Он работает очень похоже на свойства C #, IMHO, и очень прост и понятен в коде использования класса:

  check s;
int i;
std::cin >> i;
s.setX(i);
std::cout << s.x << '\n';
s.setX(7);
// s.x = i; // Error
std::cout<<s.x<<'\n';

16

Решение

соответствует ли этот код передовой практике?

Не совсем, так как это вносит ненужную сложность и накладные расходы.

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

Кроме того, что происходит с временем жизни и семантикой?

Попробуйте назначить один check в своем коде другой и посмотри что получится. Назначение плохо сформировано, потому что класс не присваивается. Вы должны предоставить конструктор копирования и перемещения, чтобы позаботиться о ссылке, чтобы он не ссылался на элемент данных старого объекта.

Лучше использовать _x напрямую и имеют прямую встроенную функцию получения.


PS: C # -подобные свойства в нативном C ++?

19

Другие решения

Как правило, это не хорошая практика.

ИМХО, и очень легко и чисто в коде использования класса.

Почему это должно быть яснее и проще?

  • Вы вводите другой член переменной (бесполезные накладные расходы). (Как правило, ссылка будет реализована как указатель на дополнительный элемент).
  • Это делает код сложнее поддерживать. Вы фактически создаете зависимости среди переменных членов.
  • Это делает проблему в назначении и в операциях копирования. Как должна работать операция копирования?

«Классический» подход мне понятнее, например:

class Foo {
public:
void set_num(int value) noexcept { m_num = value; }
int get_num() const noexcept { return m_num; }
void set_string(std::string value) noexcept {
m_str = std::move(value);
}
const std::string& get_string() const noexcept {
return m_str;
}
private:
int m_num;
std::string m_str;
};

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

  • Сроки сложности: вызов get_variable на в соответствии Функция не вносит больше накладных расходов, чем ваш «эталонный подход». Более того, он очень оптимизируемый компилятором (из-за простоты кода).
  • Сложность пространства: не вводит дополнительный элемент данных.
6

То, что вы предлагаете, является в целом плохой идеей:

  • Вы не можете реализовать свойство, выполняя какую-либо обработку (например, с помощью получателя вы можете сохранить координаты, используя [x, y], а затем решите изменить реализацию, чтобы использовать [угол, радиус], сохраняя тот же открытый интерфейс).
  • Использование переменной-члена const связано с нехваткой места и не дает никакого преимущества в производительности по сравнению со встроенным геттером.
  • Это не идиоматично.
  • После того, как вы опубликовали свой класс, и другие люди начали его использовать, вы застряли с ним: уже слишком поздно менять его на использование метода вместо него.

Если вы намерены использовать свойства, чтобы сделать код более лаконичным, вам не нужно использовать слова «get» и «set» в именах функций; это старомодная практика. Вы можете использовать фактическое имя «свойства» в качестве имени функции, и вы можете перегрузить геттер и сеттер:

class Cheque {
public:
int x() const {
return x_;
}
Cheque & x(int newX) {
x_ = newX;
return *this;
}
private:
int x_;
}

// Usage:
// int amt = myCheque.x(1234);
// Cheque c = Cheque().x(123);

возврате *this как в приведенном выше коде позволяет использовать метод цепочки; способ реализации Свободный интерфейс идиома.

4

Когда C # компилирует свойства, он компилируется в функцию получения и установки.

Вот код C #, который доказывает этот факт:

using System;

namespace Reflect
{
class Program
{
class X
{
public int Prop { get; set; }
}

static void Main(string[] args)
{
var type = typeof(X);
foreach (var method in type.GetMethods())
{
Console.WriteLine(method.Name);
}
Console.ReadKey();
}
}
}

Ваш вывод должен быть:

get_Prop
set_Prop
ToString
Equals
GetHashCode
GetType

get_Prop это функция, которая реализует геттер.
set_Prop это функция, которая реализует сеттер.

Так что даже если то, что вы делаете, выглядит одинаково, это совсем не то же самое.

Честно говоря, почти все, что вы можете сделать, чтобы попытаться эмулировать «синтаксис свойств» в C ++, рухнет так или иначе. Большинство решений будут стоить вам памяти или будут иметь некоторые ограничения, которые делают его более громоздким, чем полезным.

Просто учитесь жить с добытчиками и сеттерами.
Геттеры и сеттеры хорошая практика.
Они короткие, они простые, они гибкие, они, как правило, хорошие кандидаты на встраивание, все понимают, что они делают и так далее.

1
По вопросам рекламы [email protected]