C ++ Доступ к производному члену класса из указателя базового класса - PullRequest
34 голосов
/ 13 марта 2010

Если я выделю объект класса Derived (с базовым классом Base) и сохраню указатель на этот объект в переменной, которая указывает на базовый класс, как я могу получить доступ к членам Derived класс?

Вот пример:

class Base
{
    public:
    int base_int;
};

class Derived : public Base
{
    public:
    int derived_int;
};

Base* basepointer = new Derived();
basepointer-> //Access derived_int here, is it possible? If so, then how?

Ответы [ 5 ]

56 голосов
/ 13 марта 2010

Нет, вы не можете получить доступ к derived_int, потому что derived_int является частью Derived, а basepointer является указателем на Base.

Вы можете сделать это наоборот:

Derived* derivedpointer = new Derived;
derivedpointer->base_int; // You can access this just fine

Производные классы наследуют члены базового класса, а не наоборот.

Однако, если ваш basepointer указывал на экземпляр Derived, вы можете получить к нему доступ через приведение:

Base* basepointer = new Derived;
static_cast<Derived*>(basepointer)->derived_int; // Can now access, because we have a derived pointer

Обратите внимание, что сначала вам нужно изменить свое наследование на public:

class Derived : public Base
10 голосов
/ 13 марта 2010

Вы танцуете на минном поле здесь. Базовый класс никогда не может знать, что это на самом деле экземпляр производного. Самый безопасный способ сделать это - ввести виртуальную функцию в базу:

class Base 
{ 
protected:
 virtual int &GetInt()
 {
  //Die horribly
 }

public: 
 int base_int; 
}; 

class Derived : Base 
{ 
  int &GetInt()
  {
    return derived_int;
  }
public: 
int derived_int 
}; 

basepointer->GetInt() = 0;

Если basepointer указывает на что-то отличное от Derived, ваша программа ужасно умрет, что является ожидаемым результатом.

В качестве альтернативы вы можете использовать dynamic_cast<Derived>(basepointer). Но для этого вам нужна хотя бы одна виртуальная функция в Base, и будьте готовы встретить ноль.

static_cast<>, как некоторые предполагают, это верный способ выстрелить себе в ногу. Не вносите вклад в обширную тайну страшных историй о «небезопасности семейства C».

7 голосов
/ 09 октября 2012

вы можете использовать CRTP

вы в основном используете производный класс в шаблоне для базового класса

4 голосов
/ 10 сентября 2014

Это возможно, если сообщить базовому классу тип производного класса. Это можно сделать, сделав базовый класс шаблоном производного типа. Эта идиома C ++ называется странно повторяющийся шаблон .

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

template<typename DerivedT>
class Base
{
public:
    int accessDerivedField()
    {
        auto derived = static_cast<DerivedT*>(this);
        return derived->field;
    }
};


class Derived : public Base<Derived>
{
public:
    int field;
};

int main()
{
    auto obj = new Derived;
    obj->accessDerivedField();
}
0 голосов
/ 17 февраля 2017

// если вы знаете, какой производный класс вы собираетесь использовать

Derived * Производный указатель = dynamic_cast basepointer;

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

...