2016-06-02 7 views
1

В приведенном ниже коде список инициализаторов инициализируется с помощью объекта B и C, чьи чарты проходят со значениями «bbb» и 333 соответственно. Поскольку эти объекты происходят от A, список правильно создает два элемента A.Инициализация времени выполнения компиляции и время выполнения, доступ к вектору initializer_list, содержащему производные элементы

#include <string> 
#include <vector> 
#include <iostream> 

struct A 
{ 
    char ch; 
}; 

struct B : A 
{ 
    B(std::string str) : str(str) {} 
    std::string str; 
}; 

struct C : A 
{ 
    C(int num) : num(num) {} 
    int num; 
}; 

struct D 
{ 
    D(std::initializer_list< A* > initializerList) 
    : variadicVect(initializerList) 
    {} 

    std::vector< A* > variadicVect; 
}; 

int main() 
{ 
    D d { new B { "bbb" }, new C { 333 } }; 
    d.variadicVect[ 0 ]->ch = 'm'; // ok, but accesses base member 
    //std::cout << d.variadicVect[ 0 ]->str << std::endl; // error C2039: 'str': is not a member of 'A' 
    //std::cout << d.variadicVect[ 1 ]->num << std::endl; // error C2039: 'num': is not a member of 'A' 

    return 0; 
} 

Аналогичная проблема сообщалось в link разрешаемые @ Jarod42. В качестве проблемы он определил Object Slicing. Чтобы избежать этой проблемы с присваиванием по умолчанию, я новичок в объекте списка инициализаторов, но до сих пор не могу получить доступ к производному классу.

Еще одна попытки, я попытался была templatize в initializer_list типа (код не показан), но я получил эту ошибку: «D :: variadicVect»: только шаблоны членов статических данных разрешены»

Моей цели должна быть способный инициализировать список различными производными объектами, выбирая производный тип во время компиляции и тем не менее иметь доступ к ним должным образом во время выполнения. Это возможно?

+1

Подумайте, что вы просите код. У вас есть 'std :: vector' указателей' A'. Знает ли 'A' о членах, к которым вы пытаетесь получить доступ? – NathanOliver

+0

В этом коде нет нарезки. Связанный вопрос существенно отличается. Проблема в этом коде заключается в том, что 'A' не имеет члена' str', поэтому вы не можете применить '-> str' к' A * '. –

ответ

3

Для того, чтобы ваш код скомпилировать вы должны бросить свои векторные элементы для соответствующих типов:

std::cout << static_cast<B*>(d.variadicVect[ 0 ])->str << std::endl; 
std::cout << static_cast<C*>(d.variadicVect[ 1 ])->num << std::endl; 

иначе C++ рассматривает их как типа А, и только интерфейс от A доступен.

Другое решение - добавить виртуальные функции (virtual std::string Str(){return "";} и virtual int Num(){return 0;}) в A и переопределить их в базовых классах, где необходимо. Тогда вам не придется бросать. Пример ниже:

http://coliru.stacked-crooked.com/a/ed7c73a5d8afa5e9

#include <string> 
#include <vector> 
#include <iostream> 

struct A 
{ 
    char ch; 
    virtual std::string Str() { return ""; } 
    virtual int Num() { return 0; } 
}; 

struct B : A 
{ 
    B(std::string str) : str(str) {} 
    std::string str; 
    std::string Str() override { return str; } 
}; 

struct C : A 
{ 
    C(int num) : num(num) {} 
    int num; 
    int Num() override { return num; } 
}; 

struct D 
{ 
    D(std::initializer_list< A* > initializerList) 
    : variadicVect(initializerList) 
    {} 

    std::vector< A* > variadicVect; 

}; 

int main() 
{ 
    D d { new B { "bbb" }, new C { 333 } }; 
    d.variadicVect[ 0 ]->ch = 'm'; // ok, but accesses base member 
    std::cout << d.variadicVect[ 0 ]->Str() << std::endl; 
    std::cout << d.variadicVect[ 1 ]->Num() << std::endl; 

    return 0; 
} 
+0

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

+0

На самом деле static_cast не так уж и хорош, если вы случайно добавите экземпляр неправильного типа, вы получите UB во время выполнения. Лучшим aproach является создание шаблона D, это будет ловить любые такие ошибки во время компиляции. – marcinj

+0

Просьба подробно остановиться на создании шаблона D. Я не вижу, как это повлияет на векторные объекты A *. – rtischer8277

0

Этот вопрос был аккуратно косвенно ответил на еще один из моих проводок (см его редактирования раздел для моего объяснения, почему она так долго для меня, чтобы выяснить, какой правильный вопрос был, после чего решения - подобные союзу классы - это просто вопрос правильного создания конструкторов и деструкторов): using a union-like class in an std::initializer_list.