C почему это возвращается?

#c #qt #polymorphism

#c #qt #полиморфизм

Вопрос:

Я написал класс ‘clsFileThread’, этот класс является производным от ‘clsThread’. ‘clsThread’ является производным от ‘QThread’

В другом классе я написал метод access, который возвращает указатель на ‘QObject’. В этом методе есть что-то вроде:

 QObject* clsScriptHelper::use(QJsonValue strModule) {
    QObject* pobjModule = nullptr;

    if (strModule.toString().compare("fileIO") == 0) {
        pobjModule = new clsFileThread();
    }
    return pobjModule;
}
  

Когда указатель возвращается, это указатель на ‘clsThread’, почему? Я бы подумал, что указатель будет иметь тип QObject, тогда, используя полиморфизм, я мог бы получить доступ к элементам и методам выше, но это не так.

Что я хочу иметь возможность сделать, так это получить доступ к методам ‘clsFileThread’ через указатель, возвращаемый ‘use’, но это не работает.

Комментарии:

1. Именно так работает наследование. Через указатель на базовый класс можно получить доступ только к членам, известным базовому классу. Вызовы виртуальных функций (которые могут напрямую обращаться к производным элементам, поскольку они являются членами производного класса) разрешаются к их наиболее производным вариантам, если вы специально не принудительно вызываете базовую версию функции. Любые члены, которые есть у производных классов, которые не известны базовому классу, недоступны, если вы специально не приведете базовый указатель к указателю соответствующего производного класса.

2. Как вы пришли к выводу, что возвращаемый указатель является указателем на clsThread ? (Что говорит вам об этом? О чем именно это что-то говорит вам?)

3. @Peter, мое понимание полиморфного поведения заключается в том, что к классу можно получить доступ как к его производному классовому типу, возвращая указатель на тип базового класса.

4. @JaMit, потому что это именно то, что сообщается, когда я смотрю на тип, сообщаемый возвращаемым указателем.

5. @SPlatten Как вы смотрите на тип, «сообщаемый» возвращаемым указателем? У указателя нет встроенного способа сообщать о чем-либо. (У него нет методов.) Тип указателя, возвращаемого этой функцией, является тем, что объявлено: «указатель на QObject «. Еще раз: что говорит вам о том, что возвращаемый указатель является указателем на clsThread ? (Я почти уверен, что ваша программа не записывает std::out что-то вроде «Я получил указатель на clsThread» . Итак, что говорит вам об этом?)

Ответ №1:

Возвращаемый указатель имеет тип QObject* , хотя сам объект является типом clsFileThread* (потому что именно так вы определили use метод). Следовательно, прямой доступ к возвращаемому значению не позволит получить доступ к методам clsFileThread .

Наследование класса выглядит следующим образом:

 clsFileThread > clsThread > QThread > QObject
  

Если вы хотите получить доступ к возвращаемому объекту, как если бы это был clsFileThread, вы можете dynamic_cast возвращаемое значение, например:

 QObject* obj = clsScriptHelper::use(whatever);
clsFileThread* clsFileThreadObject = dynamic_cast<clsFileThread*>(obj);
if (clsFileThreadObject)
{
   clsFileThreadObject->doSomething();
}
  

Комментарии:

1. Это предполагает, что приведение допустимо. dynamic_cast возвращает nullptr , если obj на самом деле не указывает на clsFileThread .

2. @Peter, я бы согласился с тобой по поводу QObject *, однако, как упоминалось в моем посте, это не то, что я вижу, возвращаемый тип является экземпляром clsThread*

3. @Peter, предполагается, что полиморфизм работает не так, должно быть вполне возможно вернуть указатель типа базового класса, а затем получить доступ к объекту через его базовый класс и методы доступа в производных классах без необходимости повторного приведения указателя.

4. @SPlatten Только в том случае, если методы были объявлены virtual в базовом классе. Базовый класс волшебным образом не будет знать о методах, которые существуют только в его различных подклассах.

5. @G.M. Спасибо, я добавлю их, это имеет смысл, что не имеет смысла, когда я смотрю на это в отладчике, «this» отображается не как экземпляр clsFileThread, а как экземпляр clsThread.