2013-12-18 4 views
0

У меня есть следующие классы шаблонов: Мне нужно выяснить, как реализовать оператор преобразования между производными классами шаблонов.Оператор преобразования между шаблонами, производными классами

template<class T> 
class Base 
{ 
public: 
    Base() { } 

    template <class U> 
    operator Base<U>() 
    { 
     return Base<U> (v); 
    } 

    virtual double getV() = 0; 

}; 

class D1: public Base<D1> 
{ 
public: 

    D1(int j) 
    { 
     i = j; 
    } 

    double getV() const { return i; } 

    template <class U> 
    operator Base<U>() 
    { 
     return Base<U>(getV()); 
    } 

private: 
    int i; 
}; 

class D2: public Base<D2> 
{ 
public: 

    D2(int j) 
    { 
     i2 = j; 
    } 

    double getV() const { return i2; } 

    template <class U> 
    operator Base<U>() 
    { 
     return Base<U>(getV()); 
    } 

private: 
    int i2; 
}; 

Как я могу достичь следующего?

D1 d1(3); 
D2 d2 = d1; //conversion from 'D1' to non-scalar type 'D2' requested 

Если сам дизайн звучит или я должен делать что-то еще?

Пожалуйста, дайте мне знать, что ур мысли

+0

две проблемы: 1) у вас в классе '' Base' виртуальный ИНТ getV() ', но в его производных классов это' INT getV() const' (другая функция). 2) Вы не можете вернуть экземпляр абстрактного класса (из оператора преобразования в 'Base'). – dyp

+0

@DyP это была опечатка, исправленная 1, для вопроса 2, компилятор не возражает об этом – user3113652

+0

* «компилятор не возражает об этом» * возможно, потому что он не может знать в этой точке, если существуют специализации «Base » 'которые не являются абстрактными. Однако, если эта функция создана для базы Base , которая является абстрактной, компилятор должен жаловаться. – dyp

ответ

0

В вашем примере я не вижу причины, по которой используется CRTP.

Специализации Base имеют функцию виртуального члена, которая не зависит от параметра шаблона. Ваш код предполагает, что эта функция виртуального члена может использоваться для доступа ко всем данным, необходимым для создания экземпляра любого класса, полученного по специализации Base. Если мы будем придерживаться этого предположения, можно подумать:

class Base 
{ 
public: 
    virtual double getV() const = 0; 
}; 

class D1 : public Base 
{ 
    int i; 
public: 
    D1(int); 
    virtual double getV() const { return i; } 
}; 

class D2 : public Base 
{ 
    int i; 
public: 
    D2(int); 
    virtual double getV() const { return i; } 
}; 

Это все еще не позволяет конвертировать. Тем не менее, это достаточно просто добавить их здесь:

class D1 : public Base 
{ 
    int i; 
public: 
    D1(int); 
    D1(Base const& p) : D1(p.getV()) {} 
    virtual double getV() const { return i; } 
}; 

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


Если CR необходима для вещей, не показанных здесь, вы можете по-прежнему использовать общий базовый класс:

class Common_base 
{ 
public: 
    virtual double getV() const = 0; 
}; 

template<class T> 
class Base : public Common_base 
{ 
}; 

class D1 : public Base<D1> 
{ 
    int i; 
public: 
    D1(int); 
    D1(Common_base const& p) : D1(p.getV()) {} 
    virtual double getV() const { return i; } 
}; 

Если по какой-то причине CRTP требуется для преобразования, вы могли еще использовать преобразования шаблона конструктора:

template<class T> 
class Base 
{ 
public: 
    virtual double getV() const = 0; // whyever 
}; 

class D1 : public Base 
{ 
    int i; 
public: 
    D1(int); 
    template<class U> 
    D1(Base<U> const& p) : D1(p.getV()) {} 
    virtual double getV() const { return i; } 
}; 
+0

Спасибо, что сработало. Причина, по которой я использую CRTP разные общие операции, которые я хочу выполнять на производных классах. а также я хочу ограничить использование только этими классами – user3113652

0

Трудно сказать, что вы пытаетесь сделать, но я не думаю, что вы можете сделать это, как описано.

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

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

Если это не работает в рамках вашей текущей задачи, возможно, вам стоит больше рассказать о том, зачем вам это нужно.

+0

В принципе, я хочу иметь общий класс и производные классы, которые могут взаимодействовать друг с другом, т. Е. Могут добавлять, умножать, присваивать и т. Д. Операции на этом. все работает по мере необходимости, кроме оператора преобразования. не уверен, как идти оттуда! – user3113652

+0

Затем, как я предложил, используйте общий базовый класс и виртуальные методы. –

0

Вы либо записываете конструктор для D2, который принимает const D1&, либо вы пишете оператор преобразования в D1, который возвращает D2. Вы должны решить, что это означает для этого преобразования и соответствующим образом выполнить преобразование.

0

Вы можете добавить конструктор в ваших производных классов, которые берут базовый шаблон:

template <class U> 
D2(const Base<U> &other) 
{ 
    i2 = other.getV(); 
} 

, но не уверен, если это будет соответствовать вашим потребностям.

+0

Спасибо, это сработало! – user3113652

Смежные вопросы