2010-05-06 9 views
5

Я делаю простую консольную игру в C++Доступ к производным членов класса с базового класса указателю

Я хотел бы знать, если я могу получить доступ пользователей из класса «entPlayer», используя указатель, который указывает на базовый класс ('Entity'):

class Entity { 
public: 
    void setId(int id) { Id = id; } 
    int getId() { return Id; } 
protected: 
    int Id; 
}; 

class entPlayer : public Entity { 
    string Name; 
public: 
    void setName(string name) { Name = name; } 
    string getName() { return Name; } 
}; 

Entity *createEntity(string Type) { 
    Entity *Ent = NULL; 
    if (Type == "player") { 
     Ent = new entPlayer; 
    } 
    return Ent; 
} 

void main() { 
    Entity *ply = createEntity("player"); 
    ply->setName("Test"); 
    ply->setId(1); 

    cout << ply->getName() << endl; 
    cout << ply->getId() << endl; 

    delete ply; 
} 

Как я могу назвать ply-> setName и т. д.?

ИЛИ

Если это не возможно, таким образом, что было бы лучше?

+1

Извините, мне пришлось изменить форматирование кода. Пустые строки сделали ваш код очень высоким! Еще один небольшой комментарий о вашем коде: придерживайтесь последовательного соглашения об именах, например. AllClassNamesLikeThis и parameter_names_like_this. Еще один нит: вы будете пинать себя в заднице позже с аббревиатурами, такими как «ent». Я, честно говоря, не могу сказать, какой должен быть entPlayer. Я думаю, что вы имеете в виду только «Player», или если вы чувствуете многословность «PlayerEntity». – allyourcode

ответ

11

Это возможно с помощью отливки. Если вы знаете, за то, что указатель указывает базовый класс на объект производного класса, вы можете использовать static_cast:

Entity* e = /* a pointer to an entPlayer object */; 
entPlayer* p = static_cast<entPlayer*>(e); 
p->setName("Test"); 

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

Entity* e = /* a pointer to some entity */; 
entPlayer* p = dynamic_cast<entPlayer*>(e); 
if (p) 
{ 
    p->setName("Test"); 
} 

Тем не менее, было бы гораздо лучше, чтобы инкапсулировать функциональность вашего класса, используя полиморфизм (то есть виртуальные функции).

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

+0

У меня был связанный вопрос, на который отвечает этот ответ: D Что я хотел знать, было «Как я могу определить, указывает ли мой базовый указатель на производный объект?».Ответ, который я получаю, - это использование dynamic_cast (работает только в том случае, если базовый класс имеет виртуальную функцию). Затем посмотрите, есть ли результат NULL. #victorybaby – allyourcode

+0

Это также (частично) отвечает на другой вопрос, который у меня был на некоторое время о C++: В чем разница между различными типами приведений? Кажется, что их очень много! – allyourcode

0

Вы можете сделать динамический бросок:

entPlayer * pPlayer = dynamic_cast<entPlayer *>(pointer_to_base); 

Это будет (в случае успеха) привести в производном указатель.

В противном случае возвращается NULL.

1

Я бы рассмотреть возможность сделать что-то вроде этого:

public: 
void setId(int id) 
{ 

    Id = id; 

} 

void virtual setName(string name) = 0; // Virtual Function 
string virtual getName() = 0; // Virtual Function 

int getId() { return Id; } 

protected: 
    int Id; 

}; 

class entPlayer : public Entity { 

    string Name; 

public: 
    entPlayer() { 

     Name = ""; 
     Id = 0; 

    } 

    void entPlayer::setName(string name) { // Must define function 

     Name = name; 
} 

string entPlayer::getName() { return Name; } // again must define function here 

}; 
0

C++ делает то, что вы пытаетесь сделать очень неудобно, потому что это, вероятно, не то, что вы должны делать, и он пытается привести вас к хорошему объектно-ориентированный дизайн. Фактически, по умолчанию compilers often disable run-time type information (RTTI), который необходим для работы dynamic_cast.

Не зная своего более широкого контекста, трудно сказать, что вы должны делать вместо этого. Я могу сказать, что если вам нужен более конкретный указатель , вы должны положить на него кольцо , вы почти наверняка не должны использовать функцию, которая возвращает Entity*, и, вероятно, есть лучший подход.

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