C ++, виртуальное наследование, странный абстрактный класс + проблема клонирования - PullRequest
0 голосов
/ 03 августа 2011

Извините за большее количество исходного кода.Там три абстрактных класса P, L, PL.Третий класс PL получен из классов P и L с использованием виртуального наследования:

template <typename T>  //Abstract class
class P
{

    public:
            virtual ~P() = 0;
    virtual P <T> *clone() const  = 0;
};

template <typename T>
P<T>::~P() {}

template <typename T>
P<T> * P <T>:: clone() const { return new P <T> ( *this ); }

template <typename T>  //Abstract class
class L
{
    public:
            virtual ~L() = 0;
    virtual L <T> *clone() const = 0;
};

template <typename T>
L<T>::~L() {}

template <typename T>
L<T> *L <T> ::clone() const { return new L <T> ( *this );}

template <typename T>
class PL: virtual public P <T>, virtual public L <T>  //Abstract class
{
    public:
            PL() : P <T>(), L<T>() {}
    virtual ~PL() = 0;
    virtual PL <T> *clone() const  = 0;
};

template <typename T>
PL<T>::~PL() {}

template <typename T>
PL<T> * PL <T> :: clone() const { return new PL <T> ( *this );}

Каждый класс имеет свою собственную реализацию метода клона.

Получены два следующих класса PA, PCиз класса P с использованием виртуального наследования:

template <typename T>
class PC : virtual public P <T>
{
    public:
            PC() : P <T> () {}
            virtual ~PC() {}
            virtual PC <T> *clone() const {return new PC <T> ( *this );}
};

template <typename T>
class PA : virtual public P <T>
{
    public:
            PA() : P <T> () {}
            virtual ~PA() {}
            virtual PA <T> *clone() const {return new PA <T> ( *this );}
};

Последние два класса PCL и PAL получают с использованием виртуального наследования от ПК и PL, PA и PL.

template <typename T>
class PCL : public PC <T>, public PL <T>
{
    public:
            PCL() : P <T> (), PC <T> (), PL <T> ()  {}
            virtual ~PCL() {}
            virtual PCL <T> *clone() const {return new PCL <T> ( *this );}
};

template <typename T>
class PAL : public PA <T>, public PL <T>
{
    public:
            PAL() : P <T> (), PA <T> (), PL <T> () {}
            virtual ~PAL() {}
            virtual PAL <T> *clone() const {return new PAL <T> ( *this );}

};

Существует диаграмма зависимостей классов:

.......... P .... L.....
........../|\..../......
........./.|.\../.......
......../..|..\/........
.......PC..PA..PL.......
.......|...|.../|.......
.......|...|../.|.......
.......|...PAL..|.......
.......|........|.......
.......PCL_____/........  

Пожалуйста, не обсуждайте это предложение :-))).У меня есть следующие 3 вопроса:

1) Правильно ли была переписана эта классовая зависимость в C ++ (прежде всего, размещение "virtual")?

2) Я не уверен, что не таксм. код, пожалуйста:

int main(int argc, _TCHAR* argv[])
{
PCL <double> * pcl = new PCL <double>(); //Object of abstract class not allowed
PAL <double> * pal = new PAL <double>(); //Object of abstract class not allowed
PL <double> *pl1 = pcl->clone(); //Polymorphism
PL <double> *pl2 = pal->clone(); //Polymorphism
return 0;
} 

Невозможно создать новые объекты классов PAL / PCL, оба класса помечены как абстрактные.Но они не абстрактны.В чем проблема?

3) Можно ли использовать полиморфизм вместе с методом clone ()?Посмотрите код выше, пожалуйста ...

Спасибо за вашу помощь ...


ОБНОВЛЕННЫЙ ВОПРОС

Я исправил код.Но появляется следующая ошибка при использовании компилятора VS 2010:

template <typename T>  //Abstract class
class P
{
    public:
    virtual ~P() = 0;
    virtual P <T> *clone() const  = 0;
};

template <typename T>
P<T>::~P() {}

template <typename T>
P<T> * P <T>:: clone() const { return new P <T> ( *this ); }


template <typename T>  //Abstract class
class L
{
    public:
    virtual ~L() = 0;
    virtual L <T> *clone() const = 0;
};

template <typename T>
L<T>::~L() {}

template <typename T>
L<T> *L <T> ::clone() const { return new L <T> ( *this );}


template <typename T>
class PL: virtual public P <T>, virtual public L <T>  //Abstract class
{
    public:
            PL() : P <T>(), L<T>() {}
    virtual ~PL() = 0;
    virtual PL <T> *clone() const  = 0; 
};

template <typename T>
PL<T>::~PL() {}

template <typename T>
PL<T> * PL <T> :: clone() const { return new PL <T> ( *this );}


template <typename T>
class PC : virtual public P <T>
{
    protected:
            T pc;
    public:
            PC() : P <T> () {}
    virtual ~PC() {}
            virtual PC <T> *clone() const {return new PC <T> ( *this );}
};

template <typename T>
class PA : virtual public P <T>
{
    public:
            PA() : P <T> () {}
    virtual ~PA() {}
            virtual PA <T> *clone() const {return new PA <T> ( *this );}
};

template <typename T>
class PCL : public PC <T>, public PL <T>
{
public:
            PCL() : P <T> (), PC <T> (), PL <T> () {}
            virtual ~PCL() {}
            virtual PCL <T> *clone() const {return new PCL <T> ( *this   );}
}; //Error using VS 2010: Error 1   error C2250: 'PCL<T>' : ambiguous inheritance of 'PC<T> *P<T>::clone(void) const'


template <typename T>
class PAL : public PA <T>, public PL <T>
{
public:
            PAL() : P <T> (), PA <T> (), PL <T> ()  {}
            virtual ~PAL() {}
            virtual PAL <T> *clone() const {return new PAL <T> ( *this );}
}; //Error VS 2010: Error   1   error C2250: 'PAL<T>' : ambiguous inheritance of 'PA<T> *P<T>::clone(void) const'


int main(int argc, char* argv[])
{
PCL <double> * pcl = new PCL <double>();
PAL <double> * pal = new PAL <double>();
PL <double> *pl1 = pcl->clone();
PL <double> *pl2 = pal->clone();
return 0;
}

Возможно, я что-то упустил ... Но g ++ компилирует этот код ОК.

Ответы [ 5 ]

3 голосов
/ 03 августа 2011

Просто несколько небольших ошибок в вашем коде:

  • Получите правильные базовые инициализаторы: PAL() : PC <T>(), PL <T>() {} Нет инициализации P<T>, которая не является прямойбаза;но [Извините, это было неправильно - вам нужно вызвать виртуальный базовый конструктор из-за виртуального наследования.] Вы должны сказать круглые скобки.

  • Объявите чисто виртуальные функции без определения: virtual L <T> *clone() const = 0;

  • Дважды проверьте, что вы хотите, чтобы PL наследовал практически от P, но не виртуально от L (но это нормально).

  • Дважды проверьте, что все ваши clone() s имеют одинаковую константность.

  • Если у вас уже естьодна чисто виртуальная функция в вашем абстрактном базовом классе, вы не должны делать деструктор чистым.Вместо этого, скажем, virtual ~T() { }.В противном случае вы все равно должны предоставить определение чистого виртуального деструктора (поскольку деструктор всегда должен вызываться): virtual T::~T() { }

2 голосов
/ 03 августа 2011

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

1 голос
/ 03 августа 2011

Это компилируется для меня с использованием VC10:

template <typename T>  //Abstract class
class P
{
public:
    virtual ~P() = 0;
    virtual P <T> *clone() const  = 0;
};

template <typename T>
P<T>::~P() {}


template <typename T>  //Abstract class
class L
{
public:
    virtual ~L() = 0;
    virtual L <T> *clone() const = 0;
};

template <typename T>
L<T>::~L() {}


template <typename T>
class PL: virtual public P <T>, virtual public L <T>  //Abstract class
{
public:
    PL() : P <T>(), L<T>() {}
    virtual ~PL() = 0;
//  virtual PL <T> *clone() const  = 0; // REMOVED!
};

template <typename T>
PL<T>::~PL() {}


template <typename T>
class PC : virtual public P <T>
{
protected:
    T pc;
public:
    PC() : P <T> () {}
    virtual ~PC() {}
    virtual PC <T> *clone() const {return new PC <T> ( *this );}
};

template <typename T>
class PA : virtual public P <T>
{
public:
    PA() : P <T> () {}
    virtual ~PA() {}
    virtual PA <T> *clone() const {return new PA <T> ( *this );}
};

template <typename T>
class PCL : public PC <T>, public PL <T>
{
public:
    PCL() : P <T> (), PC <T> (), PL <T> () {}
    virtual ~PCL() {}
    virtual PCL <T> *clone() const {return new PCL <T> ( *this   );}
};


template <typename T>
class PAL : public PA <T>, public PL <T>
{
public:
    PAL() : P <T> (), PA <T> (), PL <T> ()  {}
    virtual ~PAL() {}
    virtual PAL <T> *clone() const {return new PAL <T> ( *this );}
};


int main()
{
    PCL <double> * pcl = new PCL <double>();
    PAL <double> * pal = new PAL <double>();
    PL <double> *pl1 = pcl->clone();
    PL <double> *pl2 = pal->clone();
    return 0;
}

Обратите внимание, что мне пришлось удалить PL <T> *PL <T>::clone(), чтобы VC принял код. Проблема в том, что если у вас есть PL<T>, и вы называете его clone(), он будет статически возвращать L<T>*, а не PL<T>*, даже если динамический тип относится к классу, производному от PL<T>.

0 голосов
/ 03 августа 2011
  1. Есть несколько опечаток, которые необходимо исправить в вашем коде, но virtual с в решетке наследования верны. (Они минимум. Вы можете добавить больше; в редких случаях, когда такие решетки случается, часто лучше сделать все наследование виртуальным, чтобы защитить против будущей эволюции.)

  2. В вашем тестовом коде нет ничего плохого. После опечаток в оригинал исправлен, он прекрасно компилируется с g ++.

  3. Это возможно, и должно работать так, как вы это сделали.

0 голосов
/ 03 августа 2011

Поскольку метод клонирования в вашем классе P является абстрактным, как он определен

virtual P <T> *clone() const = 0 {};

(кстати, {} неверно). Вы должны понимать, что после создания этого шаблона это отдельный метод с совершенно другой сигнатурой от метода клонирования производных классов. Создание экземпляра шаблона ведет себя так, как будто он генерирует новый код. Таким образом, это чистый абстрактный метод, который так и не был реализован. Таким образом, каждый, кто наследует этот метод (каждый производный класс), становится абстрактным классом.


Редактировать: Что касается третьего вопроса. Время выполнения и время компиляции полиморфизма не смешиваются хорошо. Я понятия не имею, почему на земле вы хотите использовать такую ​​сложную структуру, но я уверен, что дизайн может быть значительно упрощен.

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