Объявление класса без определения в C ++ - PullRequest
2 голосов
/ 17 марта 2012

У меня нет большого опыта работы с C ++, и у меня есть вопрос, касающийся следующих строк из документации Qt здесь: http://qt -project.org / doc / qt-4.8 / mainwindows-application-mainwindow-h.html (строки 4-6 после комментария вверху)

 class QAction;
 class QMenu;
 class QPlainTextEdit;

Поскольку QAction, QMenu и QPlainTextEdit являются библиотечными классами Qt (нажатие на них приводит к страницам их документации), не должноони должны быть включены с помощью #include?Какой цели служит только их объявление ключевым словом «класс»?Насколько я думаю, компилятор будет думать о нем как о совершенно новом классе, не имеющем ничего общего с классом библиотеки QAction.

Однако файл 'mainwindow.cpp' (http://qt)-project.org/doc/qt-4.8/mainwindows-application-mainwindow-cpp.html) не содержит определения класса QAction, хотя его объекты используются в коде.

Чтоздесь происходит?

Редактировать: дальнейшее объяснение проблемы

Изучить метод createActions класса MainWindow (http://qt -project.org /doc / qt-4.8 / mainwindows-application-mainwindow-cpp.html ).Здесь создаются объекты класса QAction, но нигде я не могу найти определение класса QAction.

Ответы [ 4 ]

11 голосов
/ 17 марта 2012

Объявление класса, в отличие от определения этого, достаточно, чтобы компилятор осознавал тот факт, что определенное имя относится к типу, и это позволяет вам использовать тип в определенных настройках. В частности, объявленный, но еще не определенный тип является неполным типом , и вы можете использовать неполные типы несколькими способами:

  • В объявлении функции тип возвращаемого значения и типы аргумента могут быть неполными (но, конечно, не в определении функции ). *

  • Если T является неполным типом, то T* и T&, а также их CV-квалифицированные версии, являются полными типами.

Таким образом, вы можете написать следующее:

class Foo;  // we only need to know that `Foo` names a type.

struct Bar { Foo * p; };   // complete definition of `Bar`.

Foo mangle(Foo x, Foo y);  // function declaration

Вы можете объявить класс или любой тип по этому вопросу, так часто, как вам нравится. Единственное, что должно быть уникальным - это определение (откуда "Правило одного определения").

*) За одним исключением: void всегда является неполным, и вам разрешено возвращать тип void, вообще ничего не возвращая.

4 голосов
/ 17 марта 2012

Они известны как " предварительные объявления " классов.Он используется, чтобы компилятор знал, что эти символы относятся к классам, которые будут определены позже.Они могут быть использованы в заголовочном файле для объявления символа как класса, избегая включения его заголовка, который может понадобиться в некоторых случаях (например, в круглых включениях).

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

РЕДАКТИРОВАТЬ: Чтобы ответить на следующий вопрос, который вы добавили, взгляните на файл QtGui, который вы можете найти в * qt_install_dir */ включать / QtGui.В моей установке Qt 4.8 я вижу внутри:

#include "qaction.h"

Затем загляните внутрь qaction.h: вы увидите полное определение класса QAction.Включение заголовочного файла QtGui находится в самом начале вашего mainwindow.cpp, что делает QAction полным типом.

0 голосов
/ 17 марта 2012

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

Я предполагаю, что если вы посмотрите в файл .pro, вы увидите строку, которая выглядит следующим образом:

QT += core
QT += gui

Итак, вы говорите транслятору Qt и компилятору, что вы используете модули QtGui и QtCore, и в этих модулях вы определили QAction и т. Д.Таким образом, в качестве «хака» (поскольку их IDE не может обнаружить это автоматически до более поздней стадии процесса компиляции), вы предварительно объявляете классы, чтобы избежать ошибок на этапе компиляции.В конце концов, Qt вставляет модули, и все работает нормально.

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

Есливы не объявляете класс заранее, вы получите сообщение об ошибке, в котором говорится, что он не может найти ссылку на класс и т. д.

РЕДАКТИРОВАТЬ: в свете вашего недавнего обновления я предлагаю перейти наYouTube и поиск пользователя под ником: voidrealms .У него есть достойные видеоуроки C ++ Qt с объяснениями, и там он также показывает QMenu, QAction и т. Д. Он имеет более 150 видео по программированию на Qt C ++ и охватывает все: от базового Hello World вплоть до сетевого программирования и даже дальше ...Проверьте его, у него есть и другие учебники

0 голосов
/ 17 марта 2012

Тип класса полностью определяется его полностью определенным именем (не уверен, что это официальный термин, но в любом случае), которое включает его пространство имен и его имя.Неважно, был ли он получен из файла заголовка или просто объявлен in-situ .

Фактически, включение файла заголовка в основном просто вставляет текст этого заголовка вточка исходного кода, в которой появляется включение.Эффект идентичен замене #include содержимым файла заголовка с помощью вашего любимого текстового редактора.В любом случае, компилятор сам видит только один поток токенов.

Основная цель использования forward-объявлений состоит в том, чтобы ускорить компилятор за счет уменьшения количества анализируемого текста и размера символа.таблицы, которые он создает в оперативной памяти.Я считаю, что эта практика в большинстве случаев не нужна в моей собственной работе, но очень большие проекты, вероятно, все еще приносят пользу.

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