把数据放在类声明中?

时间:2012-09-14 07:11:16

标签: c++ object declaration

one of Stroustrup's faq question中,他举了以下例子:

template<class Scalar> class complex {
public:
    complex() : re(0), im(0) { }
    complex(Scalar r) : re(r), im(0) { }
    complex(Scalar r, Scalar i) : re(r), im(i) { }
    // ...

    complex& operator+=(const complex& a)
        { re+=a.re; im+=a.im; return *this; }
    // ...
private:
    Scalar re, im;
};

并描述:

此类型旨在用作内置类型,声明中需要表示,以便可以创建真正的本地对象(即在堆栈上分配的对象)并且不在堆上)并确保简单操作的正确内联

有人可以帮忙解释一下吗?在类声明中放置reim数据会使类对象在堆栈上分配?内联怎么样? (我可以看到内联operator+=,他的意思是这个吗?)

3 个答案:

答案 0 :(得分:3)

这是一个不打算派生的具体类(因为没有必要)。

您可能不希望为复数定义接口,并导出不同类型的复数(无论是什么)并以多态方式使用它们。

通过在类中包含所有内容,编译器可以比使用抽象接口和虚函数时更容易地优化它。

我认为这里没有什么神奇之处,它只是一个使用“值类型”类合适的例子。

答案 1 :(得分:3)

成员reim分配在每个complex对象中。这意味着reim在堆栈上分配,当且仅当整个complex对象时。如果complex对象是全局对象,那么reim既不在堆栈上也不在堆上。

实际上,编译器会将re放在对象的偏移0处,将im放在偏移sizeof(Scalar)处。这意味着operator+=的代码不需要很多汇编指令来获取这些成员。实际的添加本身可能只是两个汇编指令,因此加载4个成员并存储两个结果是工作的主要部分。如果内联很少,内联工作效果最好。

答案 2 :(得分:1)

将数据放在类定义中不会生成对象 在堆栈上分配,但它允许它。在对象的位置 定义后,编译器必须知道它的完整大小;如果对象是 在堆栈上定义,编译器必须知道它的大小 定义它的翻译单位。

不将数据放入类定义意味着您必须采用 将数据分配到其他地方的一些步骤,以及其他地方的数据 几乎肯定涉及动态分配。

类似地,内联函数只能操纵它看到的数据。

有许多模式可以避免类中的数据声明。 它们具有重要的优势,特别是在数据类型时 复杂和用户定义。它们都涉及动态分配。什么 Stroustrup说,对于小型,具体的类,放置数据 在类中允许它们像内置一样表现(和执行) 类型,没有动态分配,并且经常(因为内联)没有 抽象惩罚。