C++ 类的只读成员变量

C++ 类的只读成员变量,c++,c++11,C++,C++11,根据答案,我对只读成员变量使用以下解决方案: template <class T, class OWNER> class readonly { friend OWNER; public: explicit readonly(const T &t) : m_t(t) { } ~readonly() { } operator const T&() const { return m

根据答案,我对只读成员变量使用以下解决方案:

template <class T, class OWNER>
class readonly
{
    friend OWNER;

public:
    explicit readonly(const T &t) : m_t(t)
    {
    }

    ~readonly()
    {
    }

    operator const T&() const
    {
        return m_t;
    }

private:
    T& operator =(const T &t)
    {
        m_t = t; 
        return m_t;
    }

    T m_t;
};
模板
类只读
{
朋友所有者;
公众:
显式只读(常量T&T):m_T(T)
{
}
~readonly()
{
}
运算符常量T&()常量
{
返回m_t;
}
私人:
T&T运算符=(常数T&T)
{
m_t=t;
返回m_t;
}
T m_T;
};
这非常有效,为了稍微优化性能,我使用它如下:

class A
{
public:
    A()
    {
    }

    ~A()
    {
    }

#ifdef _DEBUG     // DON'T USE THIS SWITCH, SEE ANSWERS BELOW!
    readonly<int, A> m_x, m_y;
#else
    int m_x, m_y;
#endif
};
A类
{
公众:
()
{
}
~A()
{
}
#如果不使用此开关,请参阅下面的答案!
只读m_x,m_y;
#否则
int m_x,m_y;
#恩迪夫
};
然而,我想取消预编译器开关,它检查我们是否正在进行调试或发布构建。。。有人看到使用宏或聪明的模板技巧的解决方案吗

编辑:我在一个循环中检查了性能,它使用VS2010产生了大约15~20%的开销。它不会产生相同的代码,启用了自动内联


编辑#2:我创建了一个单元测试,消除了所有其他东西。我再也没有性能损失了,太棒了,毕竟没有问题。谢谢你的帮助!我已经修复了构造函数,很好的调用。

使用助手元函数:

template< typename T, typename Owner >
struct make_read_only
{
#ifdef _DEBUG
    typedef readonly< T, Owner > type;
#else
    typedef T type;
#endif
};
模板
结构使\u只读
{
#ifdef_调试
typedef readonlytype;
#否则
T型;
#恩迪夫
};
并将您的会员声明更改为:

make_read_only< int, A >::type;
make_read_only::type;

您的优化是无用的,将产生完全相同的代码。所有的
readonly
都很简单,并且都是内联的,消除了使用raw T可能带来的任何开销。因此,解决方案是不修复不存在的问题,而只使用
readonly
,不管这是否是调试构建


正如@MooingDuck所指出的,您应该将构造函数更改为使用init list(并可能使其显式化)。

常量修饰符没有性能方面。如果有一个好的优化器,您的调试版本和发布版本将产生相同的代码。

我不是100%确定,但似乎不可能用模板来完成。因为模板无法读取预处理器变量。为了使代码更具可读性,您可以定义READONLY_INT之类的宏,并在其他.h文件中声明它。

您的方法遇到了一个很大的问题:它可以在调试和发布模式下生成不同的代码。在这里,我考虑的不是性能,而是语义。如果优化器不能生成等效的二进制文件,我会感到惊讶

在调试版本中,每当使用元素时都需要用户定义的转换,但在版本中,该转换会被删除,这反过来会启用不同的用户定义转换,并导致在将成员属性作为参数传递给函数时选择不同的重载


虽然这可能不是常见的情况,但如果您点击了它,您将面临大量的调试痛苦,试图确定为什么应用程序在发布时始终失败,但您无法使用调试版本对其进行调试…

这里有一个稍微不同的观点。 如果您想要一个只读变量,但不希望客户端必须更改其访问方式,请尝试以下模板类:

template<typename MemberOfWhichClass, typename primative>                                       
class ReadOnly {
    friend MemberOfWhichClass;
public:
    inline operator primative() const                 { return x; }

    template<typename number> inline bool   operator==(const number& y) const { return x == y; } 
    template<typename number> inline number operator+ (const number& y) const { return x + y; } 
    template<typename number> inline number operator- (const number& y) const { return x - y; } 
    template<typename number> inline number operator* (const number& y) const { return x * y; }  
    template<typename number> inline number operator/ (const number& y) const { return x / y; } 
    template<typename number> inline number operator<<(const number& y) const { return x <<y; }
    template<typename number> inline number operator>>(const number& y) const { return x >> y; }
    template<typename number> inline number operator^ (const number& y) const { return x ^ y; }
    template<typename number> inline number operator| (const number& y) const { return x | y; }
    template<typename number> inline number operator& (const number& y) const { return x & y; }
    template<typename number> inline number operator&&(const number& y) const { return x &&y; }
    template<typename number> inline number operator||(const number& y) const { return x ||y; }
    template<typename number> inline number operator~() const                 { return ~x; }

protected:
    template<typename number> inline number operator= (const number& y) { return x = y; }       
    template<typename number> inline number operator+=(const number& y) { return x += y; }      
    template<typename number> inline number operator-=(const number& y) { return x -= y; }      
    template<typename number> inline number operator*=(const number& y) { return x *= y; }      
    template<typename number> inline number operator/=(const number& y) { return x /= y; }      
    template<typename number> inline number operator&=(const number& y) { return x &= y; }
    template<typename number> inline number operator|=(const number& y) { return x |= y; }
    primative x;                                                                                
};      
模板
类只读{
谁的朋友;
公众:
内联运算符primative()常量{return x;}
模板内联布尔运算符==(常量编号&y)常量{return x==y;}
模板内联编号运算符+(常量编号&y)常量{返回x+y;}
模板内联数字运算符-(const number&y)const{return x-y;}
模板内联编号运算符*(常量编号&y)常量{return x*y;}
模板内联编号运算符/(常量编号&y)常量{返回x/y;}
模板内联编号运算符y;}
模板内联数字运算符^(const number&y)const{return x^y;}
模板内联数字运算符|(const number&y)const{return x | y;}
模板内联数字运算符&(const number&y)const{return x&y;}
模板内联数字运算符&&(const number&y)const{return x&&y;}
模板内联数字运算符| |(const number&y)const{return x | | y;}
模板内联数字运算符~()常量{return~x;}
受保护的:
模板内联编号运算符=(常量编号&y){return x=y;}
模板内联编号运算符+=(常量编号&y){return x+=y;}
模板内联编号运算符-=(常量编号&y){return x-=y;}
模板内联编号运算符*=(常量编号&y){return x*=y;}
模板内联编号运算符/=(常量编号&y){return x/=y;}
模板内联编号运算符&=(常量编号&y){返回x&=y;}
模板内联编号运算符|=(常量编号&y){返回x |=y;}
灵长类x;
};      
示例用法:

class Foo {
public:
    ReadOnly<Foo, int> x;
};
class-Foo{
公众:
只读x;
};
现在您可以访问Foo.x,但不能更改Foo.x!
请记住,您还需要添加位运算符和一元运算符!这只是一个开始的示例

我更喜欢这两种解决方案

第一种方法使用私有内联

class A
{
    public:
        inline int GetI();
        {
            return i;
        }

    private:
        int i;
}
class A
{
    public:
        const int I;

        void SetI(int newI)
        {
            //Verify newI or something.

            const_cast<int>(I) = newI;
        }
}
第二种方法使用常量和常量投射

class A
{
    public:
        inline int GetI();
        {
            return i;
        }

    private:
        int i;
}
class A
{
    public:
        const int I;

        void SetI(int newI)
        {
            //Verify newI or something.

            const_cast<int>(I) = newI;
        }
}
A类
{
公众:
常数int I;
void SetI(int newI)
{
//核实一下newI什么的。
const_cast(I)=newI;
}
}

什么循环?在什么环境下?同时你也意识到,即使它有开销,它也可能是可以忽略的,对吗?当它在你的主绘图中使用时,没有什么是可以忽略的