- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我正在通过 Stroustrup 的(使用 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;
};
然后要求我们定义一个 const 和一个非 const 成员函数来获取 val
。
我想知道:在任何情况下,有非 const get
函数返回 val
有意义吗?
在我看来,我们不能在这种情况下间接地改变值(value)。哪些用例需要 const 和非 const get
函数来返回成员变量?
最佳答案
非常量 setter/getter ?
Getter 和 setter 只是约定俗成的。有时使用的习惯用法不是提供 getter 和 setter,而是提供类似于
struct foo {
int val() const { return val_; }
int& val() { return val_; }
private:
int val_;
};
这样,根据实例的常量,您可以获得引用或拷贝:
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&
};
这是否是一般的好风格是一个见仁见智的问题。在某些情况下,它会导致混淆,而在其他情况下,这种行为正是您所期望的(见下文)。
无论如何,更重要的是根据类应该做什么以及你想如何使用它来设计一个类的接口(interface),而不是盲目地遵循关于 setter 和 getter 的约定(例如,你应该给方法一个有意义的名称,它表达了它的作用,而不仅仅是“假装被封装,现在让我通过 getter 访问你所有的内部结构”,这就是在任何地方使用 getter 的实际含义)。
具体例子
考虑到容器中的元素访问通常是这样实现的。作为一个玩具示例:
struct my_array {
int operator[](unsigned i) const { return data[i]; }
int& operator[](unsigned i) { return data[i]; }
private:
int data[10];
};
向用户隐藏元素并不是容器的工作(甚至 data
也可能是公开的)。您不希望根据是否要读取或写入元素来访问元素的不同方法,因此在这种情况下提供 const
和非常量重载非常有意义。
来自 get vs encapsulation 的非 const 引用
也许不是那么明显,但是提供 getter 和 setter 是支持封装还是相反,这有点争议。虽然一般来说,这个问题在很大程度上是基于意见的,但对于返回非 const 引用的 getter,它与意见无关。他们确实打破了封装。考虑
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;
};
顾名思义,此类已损坏。客户端可以简单地获取一个引用,并且类没有机会计算值被修改的次数(正如 set
所建议的那样)。一旦您返回一个非常量引用,那么关于封装,将成员公开几乎没有什么区别。因此,这仅用于此类行为是自然的情况(例如容器)。
附言
请注意,您的示例返回的是 const T&
而不是值。这对于模板代码是合理的,因为您不知道拷贝的成本,而对于 int
您不会通过返回 const int&
而不是 整数
。为了清楚起见,我使用了非模板示例,但对于模板代码,您可能宁愿返回 const T&
。
关于c++ - 定义非常量 'get' 成员函数的原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53683047/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!