Виртуальная функция ведет себя странно в наследстве? - PullRequest
1 голос
/ 01 июля 2011

Позвольте мне объяснить мою проблему, приведя пример:

#include <iostream>

class PC
{
public:
    PC():Data(0)
    {
    }
    virtual void display()
    {
        std::cout<<"The data is :"<<Data<<std::endl;
    }
protected:
    int Data;
};

class SmartPC:private PC
{
public:
    SmartPC():PC()
    {
    }
    void convert()
    {
        PC* temp=static_cast<PC*>(this);
        temp->display();
    }
    void display()
    {
        std::cout<<"The data is (in bb):"<<a<<std::endl;
    }
};

int main()
{
    SmartPC SmrtPC;
    PC* miniPC= static_cast<PC*>(&SmrtPC);
    SmrtPC.convert();
}

Согласно Скотту Мейерсу: static_cast<PC*>(this); создаст временную базовую копию SmartPC.Но temp->display(); выполнил функцию display() производного класса.Почему это так?Разве он не должен выполнять функцию display() базы, поскольку объект теперь полностью является копией базы SmartPC?

Другой вопрос заключается в том, что если я добавлю строку temp->data; в функцию convert(),он говорит, что PC::Data защищен, но я обращаюсь к нему из области производного класса, т.е. SmartPC, так почему он не работает?

Любая помощь приветствуется.

Ответы [ 2 ]

5 голосов
/ 01 июля 2011

Согласно Скотту Мейерсу: static_cast<PC*>(this); создаст временную базовую копию SmartPC.но temp->display(); выполнил функцию display() производного класса, почему это так?он должен выполнять функцию базы display(), поскольку объект теперь полностью является копией базы SmartPC.

Копия не создается, вы только приводите указатель .

Поскольку класс полиморфный, вызов функции virtual через указатель приводит к вызову «правильной» версии функции (в соответствии с динамическим типом объекта, который являетсяSmartPC *).

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

(display равно virtual также в SmartPC, даже если это явно не указано, при переопределении унаследованного подразумевается квалификатор virtualvirtual функций)

Обратите внимание, что если бы вы сделали:

PC temp(*this);

, вы бы на самом деле создали копию текущего объекта, "нарезанного", чтобы быть объектом типа PC.Это называется «разрезанием объектов» и выполняется конструктором копирования PC;чаще всего это нежелательное поведение (потому что то, что было объектом производного класса, фактически становится объектом базового класса, и полиморфизм не работает, как некоторые могут ожидать).

Другой вопрос: если я добавлю строку temp->data; в convert() функцию, она скажет, что PC::Data защищена, но я получаю к ней доступ из области видимости производного класса, например SmartPC, так почемуэто работает?

Концептуально, когда вы пытаетесь получить доступ к temp->data, вы пытаетесь получить доступ к private члену другого объекта (не важно, что temp на самом деле this), поэтому доступ запрещен.Ваши "привилегии производного класса" для доступа к protected членам работают только на this.

1 голос
/ 01 июля 2011

Это не копия класса, это ссылка на объект базового класса, и поэтому он ведет себя полиморфно, как и любой другой.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...