Переменные класса: общедоступный доступ только для чтения, но чтение/запись в частном доступе
Whoopee, не работающий в этой библиотеке сокетов на данный момент. Я пытаюсь обучить себя немного больше на С++.
С классами, есть ли способ сделать переменную доступной только для чтения публике, но читать + писать при доступе в частном порядке? например что-то вроде этого:
class myClass {
private:
int x; // this could be any type, hypothetically
public:
void f() {
x = 10; // this is OK
}
}
int main() {
myClass temp;
// I want this, but with private: it not allowed
cout << temp.x << endl;
// this is what I want:
// this to be allowed
temp.f(); // this sets x...
// this to be allowed
int myint = temp.x;
// this NOT to be allowed
temp.x = myint;
}
Мой вопрос, скроенный, заключается в том, как разрешить полный доступ к x
из f()
, но доступ только для чтения из любого места, т.е. int newint = temp.x;
разрешен, но temp.x = 5;
не разрешен? как константная переменная, но доступная для записи из f()
...
EDIT: Я забыл упомянуть, что планирую возвращать большой векторный экземпляр, используя функцию getX(), только сделает копию этого, и это не совсем оптимально. Я мог бы вернуть указатель на него, но эта плохая практика iirc.
P.S.: Где бы я опубликовал, если я просто хочу в основном показать свои знания указателей и спросить, завершено ли это или нет? Спасибо!
Ответы
Ответ 1
Конечно, вы можете:
class MyClass
{
int x_;
public:
int x() const { return x_; }
};
Если вы не хотите делать копию (для целых чисел нет накладных расходов), выполните следующие действия:
class MyClass
{
std::vector<double> x_;
public:
const std::vector<double>& x() const { return x_; }
};
Это не делает никакой копии. Он возвращает ссылку на const.
Ответ 2
Хотя я думаю, что функция getter, возвращающая const T&
, является лучшим решением, вы можете получить почти такой синтаксис, который вы просили:
class myClass {
private:
int x_; // Note: different name than public, read-only interface
public:
void f() {
x_ = 10; // Note use of private var
}
const int& x;
myClass() : x_(42), x(x_) {} // must have constructor to initialize reference
};
int main() {
myClass temp;
// temp.x is const, so ...
cout << temp.x << endl; // works
// temp.x = 57; // fails
}
EDIT. С прокси-классом вы можете получить именно тот синтаксис, который вы просили:
class myClass {
public:
template <class T>
class proxy {
friend class myClass;
private:
T data;
T operator=(const T& arg) { data = arg; return data; }
public:
operator const T&() const { return data; }
};
proxy<int> x;
// proxy<std::vector<double> > y;
public:
void f() {
x = 10; // Note use of private var
}
};
temp.x
выглядит как чтение-запись int
в классе, но только для чтения int
в main
.
Ответ 3
Это может сделать то, что вы хотите.
Если вы хотите переменную readonly, но не хотите, чтобы клиент мог изменить способ доступа к ней, попробуйте этот шаблонный класс:
template<typename MemberOfWhichClass, typename primative>
class ReadOnly {
friend MemberOfWhichClass;
public:
inline operator primative() const { return x; }
template<typename number> inline bool operator==(const number& y) const { return x == y; }
template<typename number> inline number operator+ (const number& y) const { return x + y; }
template<typename number> inline number operator- (const number& y) const { return x - y; }
template<typename number> inline number operator* (const number& y) const { return x * y; }
template<typename number> inline number operator/ (const number& y) const { return x / y; }
template<typename number> inline number operator<<(const number& y) const { return x <<y; }
template<typename number> inline number operator>>(const number& y) const { return x >> y; }
template<typename number> inline number operator^ (const number& y) const { return x ^ y; }
template<typename number> inline number operator| (const number& y) const { return x | y; }
template<typename number> inline number operator& (const number& y) const { return x & y; }
template<typename number> inline number operator&&(const number& y) const { return x &&y; }
template<typename number> inline number operator||(const number& y) const { return x ||y; }
template<typename number> inline number operator~() const { return ~x; }
protected:
template<typename number> inline number operator= (const number& y) { return x = y; }
template<typename number> inline number operator+=(const number& y) { return x += y; }
template<typename number> inline number operator-=(const number& y) { return x -= y; }
template<typename number> inline number operator*=(const number& y) { return x *= y; }
template<typename number> inline number operator/=(const number& y) { return x /= y; }
template<typename number> inline number operator&=(const number& y) { return x &= y; }
template<typename number> inline number operator|=(const number& y) { return x |= y; }
primative x;
};
Пример использования:
class Foo {
public:
ReadOnly<Foo, int> x;
};
Теперь вы можете получить доступ к Foo.x, но вы не можете изменить Foo.x!
Помните, что вам нужно добавить и побитовые и унарные операторы! Это просто пример, чтобы начать работу
Ответ 4
Существует способ сделать это с помощью переменной-члена, но, вероятно, это не рекомендуется.
Имейте приватный член, который доступен для записи, и переменную открытого элемента const, которая псевдонизирует член своего класса.
class Foo
{
private:
Bar private_bar;
public:
const Bar& readonly_bar; // must appear after private_bar
// in the class definition
Foo() :
readonly_bar( private_bar )
{
}
};
Это даст вам то, что вы хотите.
void Foo::someNonConstmethod()
{
private_bar.modifyTo( value );
}
void freeMethod()
{
readonly_bar.getSomeAttribute();
}
Что вы можете делать, и что вам нужно делать, это разные вопросы. Я не уверен, что метод, который я только что изложил, популярен и передаст много обзоров кода. Он также излишне увеличивает sizeof (Foo) (хотя и на небольшое количество), тогда как простой аксессуар "getter" не будет и может быть встроен, поэтому он также не будет генерировать больше кода.
Ответ 5
Вам нужно будет оставить его закрытым, а затем сделать функцию для доступа к значению;
private:
int x;
public:
int X()
{
return x;
}
Ответ 6
Напишите публичную функцию getter.
int getX(){ return x; }
Ответ 7
Вам нужно сделать член private
и предоставить метод public
getter.
Ответ 8
Единственный способ, которым я знаю предоставление доступа только для чтения к частным данным в классе С++, - это публичная функция. В вашем случае это будет выглядеть следующим образом:
int getx() const { return x; }
или
int x() const { return x; }
.
При создании частного элемента данных вы по умолчанию делаете его невидимым (a.k.a без доступа) к области вне класса. По сути, члены класса имеют доступ для чтения/записи к частному члену данных (при условии, что вы не указываете его как const
). friend
класса получают доступ к частным данным.
Обратитесь здесь и/или любую хорошую книгу С++ о спецификаторах доступа.
Ответ 9
но temp.x = 5; не допускается?
Это любой способ, который не разрешен в опубликованном фрагменте, поскольку он объявлен как закрытый и может быть доступен только в пределах класса.
Здесь запрашивается доступ к
cout < temp.x < епсИ;
но здесь не для -
int myint = temp.x;
Это звучит очень противоречиво.
Ответ 10
Вы можете захотеть сопоставить С# свойства для доступа (в зависимости от того, что вы собираетесь делать, для предполагаемой среды и т.д.).
class Foo
{
private:
int bar;
public:
__declspec( property( get = Getter ) ) int Bar;
void Getter() const
{
return bar;
}
}
Ответ 11
Простое решение, такое как Rob, но без конструктора:
class myClass {
private:
int m_x=10; // Note: different name than public, read-only interface
public:
const int& x=m_x;
};
int main() {
myClass temp;
// temp.x is const, so ...
cout << temp.x << endl; // works
// temp.x = 57; // fails
}
Это похоже на метод get, но короче. Интересный вопрос... что-то вроде. член const const bool; может сэкономить много геттеров... но я не знаю языков с этой функцией...