Хорошо ли использовать поле ссылки 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';
соответствует ли этот код передовой практике?
Не совсем, так как это вносит ненужную сложность и накладные расходы.
Более того, вы не сможете выполнять проверки и / или утверждения во время выполнения независимо от значения, к которому осуществляется доступ.
Кроме того, что происходит с временем жизни и семантикой?
Попробуйте назначить один check
в своем коде другой и посмотри что получится. Назначение плохо сформировано, потому что класс не присваивается. Вы должны предоставить конструктор копирования и перемещения, чтобы позаботиться о ссылке, чтобы он не ссылался на элемент данных старого объекта.
Лучше использовать _x
напрямую и имеют прямую встроенную функцию получения.
Как правило, это не хорошая практика.
ИМХО, и очень легко и чисто в коде использования класса.
Почему это должно быть яснее и проще?
«Классический» подход мне понятнее, например:
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
на в соответствии Функция не вносит больше накладных расходов, чем ваш «эталонный подход». Более того, он очень оптимизируемый компилятором (из-за простоты кода).То, что вы предлагаете, является в целом плохой идеей:
Если вы намерены использовать свойства, чтобы сделать код более лаконичным, вам не нужно использовать слова «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
как в приведенном выше коде позволяет использовать метод цепочки; способ реализации Свободный интерфейс идиома.
Когда 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 ++, рухнет так или иначе. Большинство решений будут стоить вам памяти или будут иметь некоторые ограничения, которые делают его более громоздким, чем полезным.
Просто учитесь жить с добытчиками и сеттерами.
Геттеры и сеттеры хорошая практика.
Они короткие, они простые, они гибкие, они, как правило, хорошие кандидаты на встраивание, все понимают, что они делают и так далее.