#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.