Jur*_*uri 21 c++ getter const member-functions
我正在使用Stroustrup(Programming Principles&Practice Using C++)一书学习C++.在练习中,我们定义了一个简单的结构:
template<typename T>
struct S {
explicit S(T v):val{v} { };
T& get();
const T& get() const;
void set(T v);
void read_val(T& v);
T& operator=(const T& t); // deep copy assignment
private:
T val;
};
Run Code Online (Sandbox Code Playgroud)
然后我们要求定义一个const和一个非const成员函数来获取val.
我想知道:有任何情况下get,返回非const 函数是否有意义val?
对我来说似乎更清洁,我们无法间接改变这种情况下的价值.在需要const和非const get函数返回成员变量的情况下可能会出现什么情况?
for*_*818 15
非常数吸气剂?
吸气剂和制定者仅仅是惯例.有时候使用的成语不是提供吸气剂和定位器,而是提供一些东西
struct foo {
int val() const { return val_; }
int& val() { return val_; }
private:
int val_;
};
Run Code Online (Sandbox Code Playgroud)
这样,根据实例的常量,您可以获得引用或副本:
void bar(const foo& a, foo& b) {
auto x = a.val(); // calls the const method returning an int
b.val() = x; // calls the non-const method returning an int&
};
Run Code Online (Sandbox Code Playgroud)
一般来说这是否是好的风格是一个意见问题.有些情况会导致混淆和其他情况,这种行为正是您所期望的(见下文).
在任何情况下,根据类应该做什么以及如何使用它来设计类的接口更重要,而不是盲目地遵循有关setter和getter的约定(例如,你应该给该方法一个有意义的名称它表达了它的作用,而不仅仅是"假装被封装,现在让我通过getter访问你所有的内部",这就是使用getters到处实际意味着什么).
具体例子
考虑容器中的元素访问通常是这样实现的.作为玩具示例:
struct my_array {
int operator[](unsigned i) const { return data[i]; }
int& operator[](unsigned i) { return data[i]; }
private:
int data[10];
};
Run Code Online (Sandbox Code Playgroud)
隐藏用户的元素(甚至data可以是公共的)不是容器工作.根据您是否要读取或写入元素,您不希望使用不同的方法来访问元素,因此const在这种情况下提供非const过载非常有意义.
来自get vs encapsulation的非const引用
也许不是那么明显,但提供getter和setter是否支持封装或相反是有争议的.虽然一般来说这个问题是基于大范围的意见,但对于返回非常规引用的获取者来说,并不是关于意见.他们确实打破了封锁.考虑
struct broken {
void set(int x) {
counter++;
val = x;
}
int& get() { return x; }
int get() const { return x; }
private:
int counter = 0;
int value = 0;
};
Run Code Online (Sandbox Code Playgroud)
顾名思义,该课程已被破解.客户端可以简单地获取引用,并且类没有机会计算修改值的次数(如set建议的那样).一旦你返回一个非const引用然后关于封装,那么将该成员公开就没什么区别了.因此,这仅用于这种行为是自然的情况(例如容器).
PS
请注意,您的示例返回的const T&是值而不是值.这对于模板代码来说是合理的,你不知道副本的价格有多贵,而对于int你来说,通过返回a const int&而不是a 来获得更多int.为了清楚起见,我使用了非模板示例,但对于模板化代码,您可能更愿意返回一个const T&.
首先让我改一下你的问题:
为什么要为成员提供非const getter,而不仅仅是让成员公开?
几个可能的原因原因:
谁说非const吸气剂需要只是:
T& get() { return val; }
Run Code Online (Sandbox Code Playgroud)
?它可能是这样的:
T& get() {
if (check_for_something_bad()) {
throw std::runtime_error{"Attempt to mutate val when bad things have happened");
}
return val;
}
However, as @BenVoigt suggests, it is more appropriate to wait until the caller actually tries to mutate the value through the reference before spewing an error.
Run Code Online (Sandbox Code Playgroud)
一些组织执行编码标准.这些编码标准有时由可能过度防御的人撰写.所以,你可能会看到类似的东西:
除非您的类是"普通旧数据"类型,否则不会公开数据成员.您可以根据需要为此类非公共成员使用getter方法.
然后,即使特定类只允许非const访问也是有意义的,它也不会发生.
val只是不存在?您已经给出了一个val实际存在于类实例中的示例.但实际上 - 它没有!该get()方法可以返回某种代理对象,该代理对象在分配时,突变等执行一些计算(例如,在数据库中存储或检索数据).
现在,阅读上面的项目1.或3,您可能会问"但我struct S 的确有val!" 或者"由我get()做任何有趣的事情!" - 嗯,是的,他们没有; 但您可能希望将来更改此行为.没有a get(),您所有的班级用户都需要更改他们的代码.使用a get(),您只需要对实现进行更改struct S.
现在,我不主张采用这种设计方法,但有些程序员会这样做.
get() 可由非const对象调用,允许变异,你可以这样做:
S r(0);
r.get() = 1;
Run Code Online (Sandbox Code Playgroud)
但是如果你使rconst为const S r(0),行r.get() = 1不再编译,甚至不能检索值,这就是为什么你需要一个const版本const T& get() const来至少能够检索const对象的值,这样做可以让你做到:
const S r(0)
int val = r.get()
Run Code Online (Sandbox Code Playgroud)
的成员函数的const版本尽量与一致的常量性呼叫在制造的物体,也就是说,如果对象是是常量和成员函数不可改变返回一个参考,它可能反映了财产常量性通过返回调用者一个const引用,从而保留了对象的不变性.