2014-11-28 3 views
1

Я не работал с производными классами и полиморфизмом через некоторое время, и я не могу понять, как получить доступ к элементу данных производного класса.Полиморфизм: доступ к элементам производного класса из массива базового класса

// Quick example 
class Base { 
    string data1; // data1 = "FOO" 
}; 
class ChildA : public Base { 
    string data2; 
}; 


int main() { 
Base **list; 
list = new Base*[1]; 
base[0] = new ChildA(// data2 = "BAR"); 
std::cout << base[0]->data1; // FOO 
std::cout << base[0]->data2; // Error; no member named "data2" in Base 

Возможно ли получить извлеченные данные из массива базового класса?

+0

Читайте о функциях виртуальных членов (нет полиморфизма в вашей выборке, вообще) –

+1

привилегии доступа в классах 'private' по умолчанию. –

+1

Вопрос о полиморфизме заключается в разработке вашей программы, чтобы вы не делали то, что делает ваш код. Дело в том, что вы не хотите заботиться о * специфике * типа *, особенно * не о том, как выглядят их внутренние данные. – Galik

ответ

3

Когда вы просматриваете экземпляр производного класса с помощью указателя на базовый класс, вы можете видеть только членов базового класса, поскольку, как правило, вы не знаете, какой экземпляр подтипа вы просматриваете , Точка полиморфизма и виртуальных функций заключается в том, что во многих случаях вы можете работать с экземплярами подтипов, не зная их фактического типа. Например, если вы хотите распечатать информацию об экземпляре и хотите, чтобы data2 был включен при печати ChildA, вы должны создать виртуальную функцию toString() в Base и переопределить ее в ChildA, чтобы включить data2. Затем вы можете позвонить toString(), не зная фактического типа, и если ваш экземпляр на самом деле ChildA, вы получите data2.

+0

Ах, это неутешительно. Я действительно думал, что есть способ отличить его от типа и получить данные, но, похоже, нет. Вот почему вы должны время от времени практиковать свои старые языки! – user3470131

+0

@ user3470131: Ах, я не понимал, что вы ищете приведение типов. Вы можете сделать '(static_cast (base [0])) -> data2', если вы уверены в типе, или' (dynamic_cast (base [0])) ', если вы этого не сделаете, 'NULL', если указанный вами тип не соответствует типу среды выполнения. Но если вам нужно сделать это иначе, чем для игры, вы можете пересмотреть свой дизайн. –

0

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

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

0

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

#include <iostream> 
#include <vector> 
#include <utility> 
#include <memory> 
#include <stdexcept> 

using namespace std; 

class Base { 
public: 
    Base(std::string d1 = {"FOO"}) : _data1 { std::move(d1) } {} 
    virtual ~Base() = default; // because polymorphism without a virtual base class is naughty 
    const string& data1() const { return _data1; } 

    virtual bool has_data2() const { return false; } 
    virtual const string& data2() const { 
     throw invalid_argument {"I don't have data2"}; 
    }; 

private: 
    string _data1; // data1 = "FOO" 
}; 

class ChildA : public Base { 
public: 
    ChildA(std::string d2, std::string d1 = {"FOO"}) 
    : Base { std::move(d1) } 
    , _data2 { std::move(d2) } 
    {} 

    bool has_data2() const override { return true; } 
    const std::string& data2() const override { 
     return _data2; 
    }; 

private: 
    string _data2; 
}; 

int main() 
{ 
    vector<unique_ptr<Base>> bases; 
    bases.push_back(unique_ptr<Base>(new ChildA("bob"))); 
    bases.push_back(unique_ptr<Base>(new Base("not foo"))); 

    for(const auto& p : bases) { 
     cout << p->data1() << ", " << (p->has_data2() ? p->data2() : "no data 2") << endl; 
    } 

    return 0; 
} 
Смежные вопросы