C++ 哪种方法更适合实现get/set?
实现get/set有两种方法 方法1: 分别定义get和setC++ 哪种方法更适合实现get/set?,c++,get,set,C++,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; }; 注意:在这种方法中,
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足够快:
另一种方法是(方法2):
定义两个get实体,第一个常量和另一个非常量
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.
}
第二个非常糟糕,因为它放弃了封装:您也可以将相应的字段公开,任何人都可以在您的对象不知道的情况下访问它。您无法根据正在更改的数据等执行范围检查或状态更新。首先,我认为这不是很有效
void set_data(my_class value)
{
m_data = value;
}
你可能应该通过引用来传递
void set_data(const my_class& value)
{
m_data = value;
}
至于应该选择哪种方法,请这样想——在第二种方法中,返回对内部对象的引用,用户完全可以自由地使用它。使用第一种方法,您可以控制用户可以做什么或不能做什么 任何自定义类都应始终使用引用来传递地址,而不是值类。还应避免传回非常量引用进行编辑。我的建议见下文
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;
};
第二种方法看起来非常笨拙。通常定义getter/setter:
const my_class& get_data() const
{
return m_data;
}
void set_data(const my_class& _data)
{
m_data = _data;
}
<> P>我知道这不是一个流行的答案,在我学习Python之前,C++露比是不可能的。但是既然您提供的getter和setter不进行范围检查或特殊计算,为什么不公开成员
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');
虽然像方法1这样的标准getter和setter可以提供“封装”,除非这些函数内联在头中,否则它们会增加很多开销。例如,在紧密循环中,即使使用引用而不是按值传递(这需要昂贵的内存复制操作),每次调用getter/setter都要在x86中不断添加大约8条指令,以便在堆栈上设置其激活记录以及函数的序言和尾声,这会占用宝贵的CPU时间,并且会严重影响性能。因为你是一个能手,二传手做的不多,所以你真的不需要他们
方法2实际上是许多STL容器所做的,比如使用
运算符[]
的std::vector
,其中重载相同的函数,但定义一个用于常量操作,另一个用于非常量操作。。。但是,当您可以公开访问数据成员时,您又增加了不必要的开销(也就是说,您不像STL容器那样是来自我们的一些底层指针和其他内存管理的数据成员)。如果要将其传递给的函数需要一个常量引用,那么它无论如何都不会更改成员,因此实际上没有必要创建这样的接口,除非您试图创建一个公共接口来跨一系列类访问成员。如果您正在这样做,那么您应该研究一个纯虚拟基类来定义公共接口。我觉得第一个方法是干净且易于理解的。我会选择第一种方法。这两种方法都不是好的解决方案。第一种方法对类使用值类型而不是引用,第二种方法返回一个非常量引用进行编辑,这不好。请看下面我的答案。为什么不使用公共变量?封装?这是一个过于简单的示例,getter/setter方法实际上是在执行验证还是其他功能?有很多不使用公共变量的理由。@Amir:我认为你没有完全理解你链接的文章。您编写的setter不属于本文所写的内容,对于getter,它将取决于其他设计约束,但无论用户代码做什么,您都在强制复制(考虑std::cout Value更好。当出现右值引用时,第二个表单将在可能是移动时调用副本,这既低效又可能不正确,具体取决于类型。此外,此类值副本是编译器RVO/NRVO的主要目标,通常不需要人工优化器。但是,它定义了可以通过使用swap()来改进。这将是一个很好的复制和交换。@DeadMG:除非您使用的是C++0x(在这种情况下,您将使用右值引用)这种特殊情况下的替代方案是:通过引用传递并在内部进行复制,通过值传递并交换可交换的对象。我必须同意Armen的观点:没有必要仅仅因为代码在编写过程中速度很快,而在重写之后,就让代码对当前编译器有害!同样,这段代码声明提出问题的人不理解链接的文章。+1,总的来说,真正的选择要么是选项一,使用setter进行参数设置并允许您执行检查,要么只是将成员公开。只编写两个方法将其转换为公共。大卫,很高兴你同意。我花了一段时间重新思考了我在大学里学过的必修课。你至少忘记了一种方法