哪种方法更适合实现get/set
Which method is better for implementing get/set?
有两种实现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;
};
注意:在这个方法中get是足够快的:http://cpp-next.com/archive/2009/08/want-speed-pass-by-value
另一个方法是(方法2):
定义两个get体,第一个是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的方法中哪个更好?
你知道更好的方法吗?
编辑:对于认为方法一更好的答案,在下列情况下你怎么说:
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.
}
对于任何自定义类,您应该始终使用引用来传递地址而不是值类。您还应该避免为编辑返回非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;
};
我知道这不会是c++纯粹主义者的普遍答案,在我学习Python和Ruby之前,我不会提出这种可能性…但是…既然你提供的getter和setter不做范围检查或特殊计算为什么不将成员设为public呢?
class main_class
{
public:
my_class my_data;
}
当然,你将失去getter上的const
,不能保证得到保护,但是你不能保证,因为你提供了一个set函数,它修改了成员。
第二个非常糟糕,因为它放弃了封装:您也可以将相应的字段设置为公共,任何人都可以在您的对象不知道的情况下访问它。您不能基于正在更改的数据执行范围检查或状态更新等
第二个将是一个非常糟糕的选择。使用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');
通常定义getter/setter:
const my_class& get_data() const
{
return m_data;
}
void set_data(const my_class& _data)
{
m_data = _data;
}
首先,我认为这不是很有效
void set_data(my_class value)
{
m_data = value;
}
你可能应该传递引用
void set_data(const my_class& value)
{
m_data = value;
}
至于你应该选择哪个方法,这样想——在你的第二个方法中,你返回一个对内部对象的引用,用户可以完全自由地对它做任何事情。使用第一种方法,您可以控制用户可以或不可以做什么。
虽然像方法1这样的标准getter和setter可以提供"封装",但除非这些函数内联在头文件中,否则它们会增加很多开销。例如,在紧密循环中,即使您使用引用而不是按值传递(这需要昂贵的内存复制操作),为了在堆栈上设置getter/setter的激活记录以及函数的序言和epilogue,每次调用都必须不断地在x86中添加大约8条指令,这消耗了宝贵的CPU时间,并且确实损害了性能。因为getter和setter的作用不大,所以你真的不需要它们。
方法2实际上是许多STL容器所做的,就像std::vector
与operator[]
一样,您重载相同的函数,但定义一个用于常量操作,另一个用于非常量操作…但是,当你可以公开访问数据成员时,你会增加不必要的开销(也就是说,它不像你是一些底层指针和其他内存管理的数据成员,比如STL容器)。如果你传递给它的函数需要一个常量引用,它无论如何都不会改变成员,所以真的没有必要创建这样的接口,除非你试图创建一个通用的接口来访问跨许多类的成员。如果你这样做,那么你应该查看一个纯虚基类来定义公共接口。
第二种方法看起来很尴尬。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- Cpp-Tuple使用带有变量的get
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用带有gsoap代理类的gsoap独立服务器实现http-get
- 是否可以在没有预处理器宏的情况下为"virtual" get-setter 定义默认实现
- 使用可变参数模板实现 Get (元组) 得到"parameter packs not expanded with ‘...’"错误
- get begin(VEC) / end(VEC)由它们之间的迭代器实现
- 哪种方法更适合实现get/set
- 具有通用get/set实现的属性树数据结构框架/库