实现get / set有两种方法。
方法1:
定义get和set。
class my_class
{
// ...
};
class main_class
{
public:
my_class get_data() const
{
return m_data;
}
void set_data(my_class value)
{
m_data = value;
}
private:
my_class m_data;
};
注意:在此方法中,获取足够快:http://cpp-next.com/archive/2009/08/want-speed-pass-by-value
另一种方法是(方法2):
定义两个get body,First const和另一个非const。
class my_class
{
// ...
};
class main_class
{
public:
const my_class& get_data() const
{
return m_data;
}
my_class& get_data() // Works like set.
{
return m_data;
}
private:
my_class m_data;
};
使用这些方法:
void main()
{
main_class cls;
// For method 1.
my_class data;
data = cls.get_data();
cls.set_data(data);
// For method 2.
const my_class data1;
my_class data2;
data1 = cls.get_data(); // const get invoked.
cls.get_data() = data2; // Like set beacuase non const get invoked.
}
我的问题是哪种实现get / set的方法更好?
你知道更好的方法吗?
修改: 对于认为方法1更好的答案,您在下面的情况中说了什么:
void main()
{
main_class cls;
// For method 1.
cls.get_data().do_something_else(); // Not effictive for cls, because data losts.
// For method 2.
cls.get_data().do_something_else(); // Effictive for cls.
}
答案 0 :(得分:16)
您应该始终使用任何自定义类的引用来传递地址而不是值类。您还应该避免传回非const引用进行编辑。请参阅下面的建议。
class my_class
{
// ...
};
class main_class
{
public:
const my_class & get_data() const
{
return m_data;
}
void set_data(const my_class & data)
{
m_data = data;
}
private:
my_class m_data;
};
答案 1 :(得分:11)
我知道这对于C ++纯粹主义者来说并不是一个流行的答案,在我学习Python之前,Ruby我不会提出这种可能性......但是......因为你提供的getter和setter不做范围检查或特殊计算为什么不公开会员?
class main_class
{
public:
my_class my_data;
}
当然,你将失去吸气剂上的const
并且无法保证保护,但无论如何你都无法保证,因为你提供了一个修改成员的固定功能。
答案 2 :(得分:8)
第二个是非常糟糕的,因为它放弃了封装:你也可以将相应的字段公开,任何人都可以在没有你的对象知道它的情况下访问它。您无法根据要更改的数据等执行范围检查或状态更新。
答案 3 :(得分:4)
第二个将是一个非常糟糕的选择。拥有setter的原因是能够控制用户如何修改成员变量。如果您只是向用户提供对您的成员的引用,则会失去所有控制权。
所以你几乎没有第一种方法。以下是您可能会或可能不会喜欢的两种变体:
// First Variation
// ---------------
// In this one both the setter and the getter have the same name
// (which is the same as the member they control). To get a
// variable you do `int i = foo.var()` and to set it you do
// `foo.var(6)`.
class Some
{
public:
int var() const {
return var_;
}
void var(int v) {
var_ = v;
}
private:
int var_;
};
// Second Variation
// ----------------
// You can also make the setter return a reference to `this`.
// This allows you to chain setters, which can _sometimes_ be
// more readable but it also has a few disadvantages.
class Employee
{
public:
Employee& salary(double dollars) {
salary_ = dollars;
return *this;
}
Employee& name(const string& n) {
name_ = n;
return *this;
}
private:
double salary_;
std::string name_;
};
// You can now do this...
Employee emp;
emp.name("John Barlick").salary(500.00);
// ... But this can become quite ugly if you chain a large amount
// of setters (you'd then probably have to break the lines in
// order to keep the code readable). It also is (technically)
// less efficient.
// In case you have lots of setters you could probably do this:
// emp.name("John Barlick")
// .salary(500.00)
// .some(787);
// .another('g');
答案 4 :(得分:2)
通常定义getter / setter:
const my_class& get_data() const
{
return m_data;
}
void set_data(const my_class& _data)
{
m_data = _data;
}
答案 5 :(得分:1)
首先,我认为这不是很有效
void set_data(my_class value)
{
m_data = value;
}
您应该通过引用传递
void set_data(const my_class& value)
{
m_data = value;
}
至于你应该选择哪种方法,请按照这种方式思考 - 在第二种方法中,您将返回对内部对象的引用,用户可以完全自由地使用它。使用第一种方法,您可以控制用户可以做什么或不可以做什么。
答案 6 :(得分:1)
虽然方法1之类的标准getter和settter可能提供“封装”,但除非这些函数在标题中内联,否则它们会增加很多开销。例如,在紧密循环中,即使您使用引用而不是按值传递(这需要进行昂贵的内存复制操作),仍然需要在x86中为每次调用getter / setter按顺序添加大约8条指令在堆栈上设置激活记录以及函数的序言和结尾会占用宝贵的CPU时间,并且真的会损害性能。既然你是吸气鬼,而且制定者做得不多,你真的不需要它们。
方法2实际上是许多STL容器所做的事情,比如std::vector
和operator[]
,你重载相同的函数,但是为常量操作定义一个,为非常量操作定义另一个...但是,当你可以公开访问数据成员时,你会增加不必要的开销(也就是说,它不像你是一些底层指针和其他内存管理的数据成员,就像STL容器一样)。如果你传递给它的函数需要一个恒定的引用,它不会改变成员,所以除非你试图建立一个通用接口来访问主机上的成员,否则不需要创建这样的接口课程。如果你这样做,那么你应该研究一个纯虚拟基类来定义公共接口。
答案 7 :(得分:0)
恕我直言,第二种方法看起来很尴尬。