我可以在派生类中为基类的成员设置别名而不增加类内存吗?

时间:2015-12-16 20:49:24

标签: c++

我想做这样的事情:

template <int N, typename type>
class BaseClass{
public:
    type array[N];
};

template <typename type>
class Derived : public BaseClass <1, type>{
public:
    type &alias = ( BaseClass<1, type>::array[0] );
};

但是当我使用时:

cout << sizeof( Derived <char> ) << endl;

它打印出16,我希望它打印1或5,而不是16.有没有办法这样做只需要sizeof(array[N])?为什么16?当我将BaseClass<1, type>更改为BaseClass<3, type>时,它也打印出16。

编辑:

我找到了解决这个问题的方法:

基类:

template <typename container, int N>
class BaseClass : public container {
public:
    // constructor example
    BaseClass(){
        for(int i = 0; i < N; i++)
            container::array[i] = 0;
    }

    // function examples
    BaseClass operator+( const BaseClass& arg ){
        BaseClass result;
        for( int i = 0; i < N; i++ )
            result.array[i] = container::array[i] + arg.array[i];

        return result;
    }

    friend ostream& operator << ( ostream& stream, const BaseClass& arg ){
        for( int i = 0; i < N; i++ )
            stream << arg.array[i] << ' ';
        return stream;
    }
};

对于派生类我会使用这样的东西:

template <typename type>
class container3{
public:
    union{
        type array[3];
        struct{
            type x;
            type y;
            type z;
        } ;
    };
};

class Derived : public BaseClass< container3<float>, 3 >{
public:
    Derived( float x = 0, float y = 0, float z = 0 ){
        this->x = x;
        this->y = y;
        this->z = z;
    }
}; 

现在我可以像这样使用它们:

Derived var1( 1, 2 );
Derived var2;

var2.y = 3;
var2.z = 6;

cout << var2 + var1 << endl;
cout << sizeof( Derived ) << endl;      /// this prints 12

return 0;

3 个答案:

答案 0 :(得分:1)

  

为什么打印16?

首先,这是实现定义。但这是一个似是而非的解释。

派生类中的引用会花费您指针的大小,在64位平台上,该指针可能是8个字节。基类中的1 char数组会花费您额外的字节。但是,由于对齐限制,编译器将1 + 8舍入到16,因为您的平台可能喜欢将地址对齐到8个字节。

  

我该怎么办?

摆脱参考。如果它总是指向基类中的数组,则不需要将其存储为成员。如果您认为每次拼写BaseClass<1, type>::array[0]都是太多输入,您可以添加成员函数。

type&
getit() noexcept
{
  return BaseClass<1, type>::array[0];
}

这不会增加您的对象大小。您可能还需要const重载。

答案 1 :(得分:0)

不是没有增加对象的大小,没有。

但是你可以写一个做同样事情的方法,并在你使用引用的任何地方调用该方法。它将在使用优化编译时进行内联,并且与别名相比不应导致更多开销(或任何开销,如果公共子表达式消除传递足够好,它将在您的示例中,因为别名表达式是尽可能简单。)

template <typename type>
class Derived : public BaseClass <1, type>{
public:
    type& alias() { return array[0]; }
    type const& alias() const { return array[0]; }
};

对象大小为16的原因是编译器创建的结构填充为机器字大小的倍数。这允许您创建此类结构的数组,而不必担心奇怪的对齐(并且实例之间没有间隙)。

我怀疑你的机器字大小是8字节(64位CPU)。因此,引用alias的8个字节(实际上只是指针周围的特殊语法),加上array的一个字节,加上7个字节的填充,使其达到8的倍数。 / p>

答案 2 :(得分:0)

根据C ++标准,未指定引用是否占用存储空间。因此,您只能通过尝试并查看会发生什么来调查此案例。

拥有类的引用成员意味着默认生成的复制构造函数,移动构造函数和赋值运算符不会正常工作。所以这给你的班级带来了相当大的复杂性。

当然你可以写:

type &alias() { return BaseClass<1, type>::array[0]; }

不会占用存储空间。