2016-01-09 4 views
1

У меня есть базовый класс родителя и шаблонные классы Child. Я хотел бы использовать Childs в коллекции, чтобы перечислить их полиморфным интерфейсом для родителя. Я ожидаю, что виртуальная (полиморфный) вызывает там - но у меня есть только статический набранное вызов Parent :: печать()Как использовать шаблонные дочерние классы по полиморфному базовому классу классов

#include <iostream> 
#include <vector> 
using namespace std; 

class Parent { 
public: 
    Parent() { cout << " parent ctor "; } 
    virtual void print() { cout << " Parent::print "; } 
}; 


template <typename T> 
class Child : public Parent { 
public: 
    Child(T value) : var(value) { cout << " child ctor "; } 
    virtual void print() { cout << " Child::print " << var; } 
protected: 
    T var; 
}; 

int main() { 
    Child<int> myChild(1); 
    Child<double> myDoubleChild(2.); 

    vector<Parent> v = {myChild, myDoubleChild}; 

    for (auto i : v) { 
     i.print(); 
    } 

    return 0; 
} 

Фактический выход:

parent ctor child ctor parent ctor child ctor Parent::print Parent::print 

Ожидаемый результат должен содержать " Child :: print "вызовы виртуальных функций

ответ

2

Как упоминаемый @tchelidze и @StenSoft Есть два недостатка: Строгание

  1. объекта. Хромая ошибка. станд :: вектор использует сырые объекты
  2. полиморфизм работает только с указателями или ссылками

Чтобы включить динамический код отправки должен быть таким:

#include <iostream> 
#include <vector> 
using namespace std; 

class Parent { 
public: 
    Parent() { cout << " parent ctor "; } 
    virtual void print() { cout << " Parent::print "; } 
}; 


template <typename T> 
class Child : public Parent { 
public: 
    Child(T value) : var(value) { cout << " child ctor "; } 
    virtual void print() { cout << " Child::print " << var; } 
protected: 
    T var; 
}; 

int main() { 
    Child<int> myChild(1); 
    Child<double> myDoubleChild(2.); 

// vector<Parent> v = {myChild, myDoubleChild}; 
    vector<Parent*> v = {&myChild, &myDoubleChild}; 

    for (auto i : v) { 
//  i.print(); 
     i->print(); 
    } 
    return 0; 
} 

Это дает желаемый результат:

parent ctor child ctor parent ctor child ctor Child::print 1 Child::print 2 
+1

Возможно, вы захотите использовать интеллектуальные указатели вместо необработанных указателей. – ysdx

+0

@ysdx То правда, этот код работает отлично: 'вектор > v = {make_shared > (1), make_shared > (1)};' – barney

+0

2. вызывается 1. так что то же самое вопрос – StenSoft

1

Причина: Object Slicing.
То есть:

при назначении объекта подкласса для суперкласса. Суперкласс ничего не знает о дополнительной информации в подклассе, и нет места для хранения, поэтому дополнительная информация получает «отрезала»

1

полиморфизма в C++ работает только на ссылки и указатели. vector<Parent> - вектор значений. Они создаются как копии экземпляров Child и все типа Parent. В основном то, что он делает это:

vector<Parent> v = { Parent(myChild), Parent(myDoubleChild) }; 

Если бы Parent абстрактного класса (например, путем изменения print в чистый виртуальный метод), вы увидите сообщение об ошибке.

Вам нужен вектор указателей и т.д .:

vector<unique_ptr<Parent>> 
Смежные вопросы