Свойства свойств как шаблонов - PullRequest
0 голосов
/ 28 сентября 2010

Я пытаюсь реализовать свойства 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;
        }
};

Теперь предположим, что я объявляю 2 класса, один из которых содержит другой в качестве свойства:

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;

работает без ошибок, но фактически не меняет фактическое A из B , потому что доступ ((A) b.pB1) .pA1 дает неизменное значение, поскольку, вероятно делает копию.

Есть ли способ сделать это без указателей?

Ответы [ 3 ]

2 голосов
/ 28 сентября 2010

Приведение одного объекта к другому типу приводит к временной копии, которая выходит из области видимости, как только эта строка кода завершена. Вы хотели написать ((A&) b.pB1).pA1=1;?

1 голос
/ 28 сентября 2010

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;
}
0 голосов
/ 28 сентября 2010

Вы пытались добавить оператор неконстантной функции?

operator T& () 
{
    return value;
}

Это нарушает инкапсуляцию, но ваш пример использования предполагает, что вы хотите иметь возможность изменять свойства.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...