Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么要使用函数而不是对成员的引用?_C++_Class_C++11_Reference - Fatal编程技术网

C++ 为什么要使用函数而不是对成员的引用?

C++ 为什么要使用函数而不是对成员的引用?,c++,class,c++11,reference,C++,Class,C++11,Reference,我正在测试一些代码,并注意到类似于: template<typename T> class example{ public: example(T t): m_value{t}{} const T &value = m_value; private: T m_value; }; 模板 课例{ 公众: 示例(T T):m_值{T}{} 常数T&value=m_值; 私人: T m_值; }; 我以前没见过这个

我正在测试一些代码,并注意到类似于:

template<typename T>
class example{
    public:
        example(T t): m_value{t}{}

        const T &value = m_value;

    private:
        T m_value;
};
模板
课例{
公众:
示例(T T):m_值{T}{}
常数T&value=m_值;
私人:
T m_值;
};
我以前没见过这个。我以前使用过的几乎每个API或库都定义了一个函数,该函数返回一个成员变量,而不是对它的常量引用:

template<typename T>
class example{
    public:
        example(T t): m_value{t}{}

        const T &value() const{
            return m_value;
        }

    private:
        T m_value;
};
模板
课例{
公众:
示例(T T):m_值{T}{}
常量T&值()常量{
返回m_值;
}
私人:
T m_值;
};

为什么第一种方式不那么常见?缺点是什么?

返回适当引用的(内联)函数之所以更好,有几个原因:

  • 引用将需要每个对象中的内存(通常与指针相同)

  • 引用通常与指针具有相同的对齐方式,从而导致周围的对象可能需要更高的对齐方式,从而浪费更多内存

  • 初始化引用需要(很小的)时间

  • 具有引用类型的成员字段将禁用默认的复制和移动分配运算符,因为引用不可重设

  • 拥有引用类型的成员字段将导致自动生成的默认复制和移动构造函数不正确,因为它们现在将包含对其他对象成员的引用

  • 函数可以做额外的检查,比如在调试构建中验证不变量


  • 请注意,由于内联,除了可能稍大的二进制文件外,函数通常不会产生任何额外的成本。

    第一个选项需要额外的内存,就像指针一样

    如果您这样做:

    inline const T& value() const{
          return m_value;
    }
    
    在不需要额外内存的情况下,您可以获得与第一种方法相同的好处


    另外,由于第一种方法需要C++11,人们使用它的可能性较小。

    返回常量引用的一般用法:
    在创建或销毁副本成本高昂的情况下,返回常量引用是很常见的。
    一般来说,规则是:如果传递和使用引用比复制更昂贵,不要这样做。如果您没有被要求提供子对象,通常甚至是不可能的。
    否则,返回常量引用是一种有效的性能优化,这对行为良好的源代码是透明的。
    很多模板代码返回常量引用,即使在上面的测试没有指出的地方,只是为了平等地对待所有的专业化,因为函数非常小,几乎可以保证是内联的

    现在,让我们来看看你好奇的发现(从未见过类似的东西):
    +不需要访问器函数(尽管如此,这还是很蹩脚,无论如何都会编译出来)
    -对象更大(引用通常需要与指针一样多的空间)
    -由于上述原因,可能需要更好的对齐。
    -没有魔法成员函数,因为编译器不知道如何复制引用
    -对于调试生成,不能添加其他检查

    同样的外观和感觉,没有附带的损害,可以实现像这样的顺便说一句(只有额外的检查调试保持不可能):

    模板
    结构示例{
    示例(T T):值{T}{}
    联合{
    常数T值;
    结构{
    私人:
    T值;
    朋友班榜样;
    }_值;
    };
    };
    
    封装

    对于面向对象编程的纯粹主义者来说,
    m_值
    是一个实现细节。类
    example
    的使用者应该能够使用单个可靠的接口访问
    value()
    ,而不应该依赖于
    example
    如何确定它。
    示例的未来版本(或复杂的模板专门化)可能希望在返回
    值()之前使用缓存或日志记录;或者,由于内存限制,它可能需要动态计算
    value()

    如果您最初不使用访问器函数,那么如果您以后改变主意,那么使用
    example
    的所有内容可能都必须更改。这会带来各种各样的浪费和虫子。通过提供像
    value()
    这样的访问器,更容易将其进一步抽象一级


    另一方面,有些人对这些面向对象的原则并不那么严格,他们喜欢编写高效易读的代码,在重构发生时处理重构。

    这只是风格而已。有些人只是讨厌任何类型的公共成员,有些人认为如果它们是不可变的/constant就可以了。一个主要的区别是,在第二个版本中,调用方不能使用引用来修改
    m_值
    。升级该功能以执行一些检查或预获取操作也很容易。在C++11之前,您必须在所有构造函数中初始化引用,这很繁琐,第二种方法导致对象smaller@MattMcNabb在第一个示例中,您怎么说他们可以通过
    常量编辑
    m_值
    ?@MattMcNabb这两种样式都允许通过
    常量转换修改成员。通常不需要为相同功能使用更多内存?@Deduplicator
    const T&value=m_值
    是类型为
    T const&
    ?@CoffeeandCode的成员变量,我认为数字5是真正的杀手(如果没有你的评论,我会把它弄错的^^^),我只想补充一下,这个示例不再返回副本;为了使这两个例子更加相似,我个人认为第6点从长远来看是最有问题的。这里使用函数的意义实际上是因为代码的演变。每次对类型进行可能的改进或必要的更改时,如果ac
    template<typename T>
    struct example {
        example(T t): value{t}{}
        union{
            const T value;
            struct{
            private:
                T value;
                friend class example<T>;
            } _value;
        };
    };