属性的属性作为模板

时间:2010-09-27 20:31:09

标签: c++ properties

我尝试将C ++属性实现为WikiPedia

中定义的模板
template <typename T> class property {
        T value;
    public:
        T & operator = (const T &i) {
            ::std::cout << i << ::std::endl;
            return value = i;
        }
        // This template class member function template serves the purpose to make
        // typing more strict. Assignment to this is only possible with exact identical
        // types.
        template <typename T2> T2 & operator = (const T2 &i) {
            ::std::cout << "T2: " << i << ::std::endl;
            T2 &guard = value;
            throw guard; // Never reached.
        }
        operator T const & () const {
            return value;
        }
};

现在假设我声明了两个类,其中一个包含另一个属性:

class A
{
    public:
        Property<double> pA1;
        Property<double> pA2;
};

class B
{
    public:
        Property<A> pB1;
        Property<double> pB2;
};

现在,有没有办法声明 B 并访问 A 的属性?

B b;
b.pB1.pA1=1;

不起作用;

((A) b.pB1).pA1=1;

没有错误,但实际上并没有改变 B 的实际 A ,因为访问((A)b.pB1).pA1给出了不变的值,因为它可能会复制。

有没有办法用无指针做到这一点?

3 个答案:

答案 0 :(得分:2)

将一个对象转换为另一个类型会导致临时副本在代码行完成后立即超出范围。你的意思是写((A&) b.pB1).pA1=1;吗?

答案 1 :(得分:1)

b.pB1没有pA1字段。相反,它有b.pB1.value.pA1。使用“。”实际上调用“成员访问运算符”,绕过类型转换运算符。显式类型转换有效,但从长远来看不是一个安全的代码:

((A&)b.pB1).pA1 = 1.0;

更好的方法是实现成员访问运算符。它也破坏了封装(因为可以显式调用运算符),但与显式类型转换相比更安全:

T* operator->()             { return &value; }
...
b.pB1->pA1 = 3.0;

完整的例子:

#include <iostream>
using namespace std;

template <typename T>
class Property
{
    T value;
public:
    T& operator=(const T& x) {
        return value = x;
    }
    template <typename T2>
    T2 & operator = (const T2 &i) {
        T2 &guard = value;
        throw guard; // Never reached
    }
    operator T const & () const { return value; }

    const T* operator->() const { return &value; }
    T* operator->()             { return &value; }
};

class A
{
public:
    Property<double> pA1;
    Property<double> pA2;
};

class B
{
public:
    Property<A> pB1;
    Property<double> pB2;
};

int
main()
{
    B b;

    //b.pB2 = 1;    // not allowed by guard
    b.pB2 = 1.0;

    ((A&)b.pB1).pA1 = 2.0;
    cout << "b.pB1.pA1: " << ((A&)b.pB1).pA1 << endl;

    b.pB1->pA1 = 3.0;
    b.pB1->pA2 = 4.0;
    cout << "b.pB1.pA1: " << b.pB1->pA1 << endl;
    cout << "b.pB1.pA2: " << b.pB1->pA2 << endl;

    return 0;
}

答案 2 :(得分:0)

您是否尝试过添加非const函数运算符?

operator T& () 
{
    return value;
}

这打破了封装,但您的样本使用表明您希望能够修改属性。