2010-09-27 11 views
0

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

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

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

+0

Что не работает в виду? givs ошибка? – Shaihi

ответ

2

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

+0

и есть ли способ создать свойство в B, которое ссылается непосредственно на pA1? как свойство pA1_in_B = ((A &) this-> pB1) .pA1; –

+0

@paul, я думаю, 'pA1_in_B' должен быть объявлен как ссылка для этого кода, чтобы делать то, что вы ожидаете. Теоретически вы могли бы также взять адрес всего беспорядка и работать с ним как указатель. –

0

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

operator T&() 
{ 
    return value; 
} 

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

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; 
} 
Смежные вопросы