Как подключить класс
Я вот создал проект и все как обычно: main.cpp, mainwindow.cpp и .h . И я делаю menubar, я хочу что бы оно было в другом месте, не в main.cpp, mainwindow.cpp и .h , а в созданном месте под название menu.cpp, как это сделал и еще как подключить, что-бы все, что было написано в menu.cpp, main.cpp, mainwindow.cpp и .h скомпелировалось и показалось?
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
Подписка на обсуждение 3
Подписка на раздел 235
Вам это нравится? Поделитесь в социальных сетях!

Создание нового класса:
1. В главном меню — Файл / Создать файл или проект;
2. В открывшемся окне — Файлы и классы / С++;
3. Ввести имя класса;
4. Выбрать или ввести имя базового класса ( от которого хотите наследоваться ) и подключить в заголовочном файле созданного класса соответствующий заголовочный файл ( класса предка ).
Имя класса: MyClass;
MyClass *myClass = new MyClass(); // Далее использовать методы класса: myClass->myMethod(param);

В файле mainwindow.h:
#include "myclass.h"
Посмотрите, как решить?


- Evgenii Legotckoi → tetta
- #
- 24 апреля 2017 г. 8:14
- Ответ был помечен как решение.
Во-первых, сам класс menu , нужно наследовать как минимум от QObject , а не просто помещать макрос Q_OBJECT в объявление класса menu .
Во вторых, где в классе mainwindow подключение заголовочного класса menu ?
В-третьих, метод menuBar() в классе menu вообще не существует — это метод класса QMainWindow , поэтому и работать не будет.
В-четвёртых, лучше использовать новый синтаксис сигналов и слотов .
Наверняка там ещё много косяков, но пока хотя бы это исправьте.

Если я правильно понял. то вы не хотите реализовать свой класс наследник с функционалом отличным от QMenuBar, а просто вынести описание главного меню в отдельный класс (файл).
В этом случае можно наследоваться от QMenuBar, а в классе главного окна писать setMenuBar(myClass);
Добавление класса
Чтобы добавить класс в проект Visual Studio C++, в обозревателе решений щелкните правой кнопкой мыши проект, выберите Добавить, а затем Класс. Откроется диалоговое окно Добавление класса.
При добавлении класса нужно указать имя, которое отличается от классов, уже существующих в MFC или ATL. Если указать имя, которое уже существует в одной из библиотек, интегрированная среда разработки выводит сообщение об ошибке.
Если по соглашению об именовании нужно использовать существующее имя, можно просто изменить регистр одной или нескольких букв в имени, так как C++ учитывает регистр. Например, хотя вы не можете назвать класс CDocument , можно назвать его cdocument .
Класс какого типа вы хотите добавить?
В диалоговом окне Добавление класса при развертывании узла Visual C++ на левой панели отображаются несколько групп установленных шаблонов. К этим группам относятся CLR, ATL, MFC и C++. При выборе группы на средней панели отображается список доступных шаблонов в этой группе. Каждый шаблон содержит необходимые для класса файлы и исходный код.
Чтобы создать класс, выберите шаблон в средней области, введите имя класса в поле Имя и нажмите Добавить. Откроется мастер добавления классов, где можно указать параметры для класса.
- Дополнительные сведения о создании классов MFC см. в разделе Класс MFC.
- Дополнительные сведения о создании классов ATL см. в разделе Простой объект ATL.
Шаблон Добавление поддержки ATL в MFC не создает класс, а настраивает проект для использования библиотеки ATL. Дополнительные сведения см. в разделе Поддержка ATL в проекте MFC.
Чтобы создать класс C++, который не использует MFC, ATL или CLR, воспользуйтесь шаблоном Класс C++ в группе C++ установленных шаблонов. Дополнительные сведения см. в разделе Добавление универсального класса C++.
Доступны два типа классов C++ на основе форм. Первый — класс CFormView — создает класс MFC. Второй создает класс Windows Forms для среды CLR.
Диалоговое окно «Добавление класса»
В Visual Studio 2015 диалоговое окно Добавление класса содержит шаблоны, которые позволяют выполнить следующие действия.
- Открыть соответствующий мастер создания кода, если он доступен. Дополнительные сведения см. в разделе Добавление функциональных возможностей с помощью мастеров кода. — или —
- Автоматически создать новый класс, добавив в проект соответствующие файлы и исходный код.
Перейти к диалоговому окну Добавление класса можно из меню Проект, обозревателя решений или представления классов.
При попытке добавить класс, который не подходит для текущего проекта, вы получите сообщение об ошибке. Нажмите ОК, чтобы вернуться в диалоговое окно Добавление класса.
В Visual Studio 2017 и более поздних версиях диалоговое окно Добавление класса — это диалоговое окно универсального класса C++. Дополнительные сведения см. в разделе Добавление универсального класса C++.
Диалоговое окно «Мастер классов»
Класс можно создать на основе установленных шаблонов в диалоговом окне Мастера классов. Чтобы использовать мастер классов, щелкните проект правой кнопкой мыши в обозревателе решений и выберите в контекстном меню пункт Мастер классов. При нажатии в диалоговом окне кнопки Добавить класс отображается раскрывающийся список для выбора шаблона.

Можно также использовать мастер классов для изменения или просмотра существующего класса.
Добавление шаблонов классов
Существует четыре категории шаблонов добавления классов : .NET, ATL, MFC и универсальные.
.NET
| Шаблон | Мастер |
|---|---|
| Веб-служба ASP.NET; | Недоступно |
| Класс компонента (.NET) | Недоступно |
| Класс установщика (.NET) | Недоступно |
| Пользовательский элемент управления (.NET) | Недоступно |
| Форма Windows Forms (.NET) | Недоступно |
ATL
| Шаблон | Мастер |
|---|---|
| Добавление в MFC поддержки ATL | Недоступно |
| Элемент управления ATL | Мастер элементов управления ATL |
| Диалог ATL | Мастер диалоговых окон ATL |
| Простой объект ATL | Мастер простых объектов ATL |
| Поставщик событий WMI | Мастер поставщика событий WMI |
| Поставщик экземпляров WMI | Мастер поставщика экземпляра WMI |
MFC
| Шаблон | Мастер |
|---|---|
| Класс MFC | Мастер добавления классов MFC |
Универсальные классы
| Шаблон | Мастер |
|---|---|
| Универсальный класс C++ | Мастер универсальных классов C++ |
Подключение классов
C++, Visual Studio 2013
Как правильно подключать классы, если имеется следующая структура: Файл Base.h:
class base<>;
Файл Child1.h:
#include "base.h" class Child : public base
Файл Child2.h:
#include "base.h" class Child2 : public base
Файл Main.h:
#include "Child.h" #include "Child2.h"
При таком включении получаю ошибку линковки: переопределение класса base
Отслеживать
28.5k 12 12 золотых знаков 59 59 серебряных знаков 118 118 бронзовых знаков
задан 13 апр 2016 в 10:44
73 1 1 серебряный знак 6 6 бронзовых знаков
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Скорее всего, у вас в h файлах отсутствует защита от двойного включения. Самый простой способ — добавить #pragma once в самый верх каждого .h файла или сделать по старинке — завернуть в охранный «гуард»
#ifndef _FILENAME_H_ #define _FILENAME_H_ // тут код #endif
_FILENAME_H_ — должно быть уникально для каждого файла, поэтому, обычно оно совпадает с именем файла. Этот способ работает на практически всех доступных компиляторах с/с++. pragma once может не работать на старых компиляторах.
Отслеживать
ответ дан 13 апр 2016 в 10:49
112k 6 6 золотых знаков 93 93 серебряных знака 159 159 бронзовых знаков
на практически всех . встречали случаи, где не работало?
13 апр 2016 в 11:13
да, я пользовался c комилятором, в котором не было define. Просто не было. Компилятор был по хитрые контроллеры, сейчас даже не вспомню. Автор вопроса вряд ли столкнется с подобным, но мало чего .
13 апр 2016 в 12:00
В таком случае это не может называться c компилятором в полной мере. Это просто какая-то поделка. И кстати, вопрос ТС по c++ .
13 апр 2016 в 12:07
я вкурсе, что вопрос по с++. А подделкой приходилось пользоваться, так как другого не было. А писать код прям в кодах мне не хотелось. Правда потом был прикручен препроцессор и все работало так как хотелось (да, если сильно быть педантом, обработка #ifdef — это работа препроцессора, а не компилятора. И как следствие ниодин правильный компилятор не поддерживает. Но современные компиляторы это скрывают и делают препроцессирование самостоятельно).
13 апр 2016 в 12:12
Понятно, что это работа препроцессора, но препроцессорные директивы тем не менее описаны в Стандарте по языку. И я бы отнес это к базовой части того, что реализация должна уметь. Иначе можно придумать и компиляторы, которые, скажем, не имеют оператора if . Но назвать такое компилятором си, язык не поворачивается.
Как подключить класс в c
Эта статья даст базовое понимание терминов «класс», «метод», «наследование», «перегрузка метода»
Методы
Методы — это функции, объявление которых размещено внутри определения класса или структуры. В список переменных, доступных для метода, неявно попадают все поля структуры или класса, в котором он объявлен. Другими словами, в список областей видимости метода попадает область видимости структуры.
Взгляните на пример:
#include struct Vec2f float x = 0; float y = 0; // Объявление метода с именем getLength // 1) метод - это функция, привязанная к объекту // 2) полное имя метода: "Vec2f::getLength" // Метод имеет квалификатор "const", потому что он не меняет // значения полей и не вызывает другие не-const методы. float getLength() const const float lengthSquare = x * x + y * y; return std::sqrt(lengthSquare); > >;
Методу Vec2f::getLength доступны все символы (т.е. переменные, функции, типы данных), которые были объявлены в одной из трёх областей видимости. При наличии символов с одинаковыми идентификаторами один символ перекрывает другой, т.к. поиск происходит от внутренней области видимости к внешней.
Понять идею проще на схеме. В ней область видимости названа по-английски: scope.

Поднимаясь по схеме от внутренней области видимости к внешней, легко понять, какие имена символов доступны в методе getLength:
- локальная переменная “lengthSquare”
- поля Vec2f под именами “x” и “y”
- всё, что есть в глобальной области видимости
К слову, в других методах структуры Vec2f переменная “lengthSquare” будет недоступна, а поля “x” и “y” будут доступны.
Конструкторы
Конструктор — это специальный метод, который вызывается автоматически при выполнении инструкции объявления переменной. При этом память под переменную уже выделена заранее, т.к. память под все локальные переменные выделяется на стеке программы в момент вызова функции. Конструктор позволяет выполнить сложный код для инициализации переменной.
Посмотрите на простой пример. В нём есть проблема: и поля, и параметры конструктора названы одинаково. В результате в области видимости конструктора доступны только параметры, и своими именами они перекрывают поля!
struct Vec2f float x = 0; float y = 0; // Имя метода-конструктора совпадает с именем типа, возвращаемый тип отсутствует Vec2f(float x, float y) // поля x, y перекрыты, что делать? > >;
Язык C++ предлагает два решения. Первый способ — использовать косвенное обращение к полям через привязанный к методу объект. Указатель на него доступен по ключевому слову this :
struct Vec2f float x = 0; float y = 0; Vec2f(float x, float y) // Обращаемся к полю через указатель this this->x = x; this->y = y; > >;
Второй путь считается более правильным: мы используем специальную возможность конструкторов — “списки инициализации конструктора” (англ. constructor initializer lists). Списки инициализации — это список, разделённый запятыми и начинающийся с “:”. Элемент списка инициализации выглядит как field(expression) , т.е. для каждого выбранного программистом поля можно указать выражение, инициализирующее его. Имя переменной является выражением. Поэтому мы инициализируем поле его параметром:
struct Vec2f float x = 0; float y = 0; Vec2f(float x, float y) : x(x) // Перекрытия имён нет, т.к. согласно синтаксису C++ , y(y) // перед скобками может стоять только имя поля. > >;
Объявление и определение методов
C++ требует, чтобы каждый метод структуры или класса был упомянут в определении этой структуры или класса. Но допускается писать лишь объявление метода, о определение размещать где-нибудь в другом месте:
// Определение структуры Vec2f содержит // - объявление конструктора // - объявление метода getLength struct Vec2f float x = 0; float y = 0; Vec2f(float x, float y); float getLength() const; >; // Определение конструктора (добавлен квалификатор "Vec2f::") Vec2f::Vec2f(float x, float y) : x(x) , y(y) > // Определение метода getLength (добавлен квалификатор "Vec2f::") float Vec2f::getLength() const const float lengthSquare = x * x + y * y; return std::sqrt(lengthSquare); >
Классы и структуры
В C++ есть ключевое слово class — это практически аналог ключевого слова struct . Оба ключевых слова объявляют тип данных, и разница между ними есть только на стыке наследования и инкапсуляции. Других различий class и struct не существует.
Основы инкапсуляции
В C++ можно блокировать доступ к полям извне, но сохранять доступ для методов. Для этого введены три области доступа
- public — символ в этой области доступен извне
- private — символ из этой области доступен лишь собственных в методах
- protected — используется редко, о нём можете прочитать в документации
Давайте сделаем поля типа Vec2f недоступными извне. Также мы заменим ключевое слово struct на class — это не меняет смысла программы, но считается хорошим тоном использовать struct только если все поля доступны публично.
class Vec2f public: // начало списка публичных методов и полей Vec2f(float x, float y) : x(x) , y(y) > float getLength() const // Здесь поля x/y доступны, т.к. это внутренний метод const float lengthSquare = x * x + y * y; return std::sqrt(lengthSquare); > private: // начало списка недоступных извне методов и полей float x = 0; float y = 0; >; // ! ОШИБКА КОМПИЛЯЦИИ ! // Поля x/y недоступны для внешней функции void printVector(const Vec2f& v) std::cout <"[" <v.x <"," <v.y <"]"; >
Запомните несколько хороших правил:
- Используйте struct, если все поля публичные и не зависят друг от друга; используйте class, если между полями должны соблюдаться закономерности (например, поле “площадь” круга должно быть)
Основы наследования
В C++ новый тип может наследовать все поля и методы другого типа. Для этого достаточно указать структуру или класс в списке базовых типов. Такой приём используется в SFML при объявлении классов фигур:
// ! КОД НАМЕРЕННО УПРОЩЁН! // Класс RectangleShape наследует все поля и методы Shape, // но также имеет дополнительные поля и методы. // Финальный список полей и методов составляет компилятор при сборке программы. // Смысл наследования: "прямоугольник является фигурой". class RectangleShape : public Shape public: // Конструктор, принимающий один необязательный аргумент RectangleShape(const Vector2f& size = Vector2f(0, 0)); // Метод с одним аргументом void setSize(const Vector2f& size); // . >; // Класс Shape наследует все поля и методы двух классов: Drawable и Transformable // Смысл наследования: "фигура является сущностью, которую можно нарисовать // и у которой можно задать позицию/масштаб/вращение" class Shape : public Drawable, public Transformable public: // Виртуальный деструктор Shape. // Деструктор вызывается // 1) для локальной переменной - при выходе из области видимости локальной переменной // 2) для параметра, переданного по значению - при выходе из функции // 3) для временных объектов в выражении - при завершении инструкции, в которой находится выражение // 4) для объектов в динамической памяти - при освобождении памяти (например, через delete) // Деструкторы простых типов int, sf::Vector2f и т.д. не делают ничего. // Деструкторы сложных типов освобождают ресурсы (например, удаляют текстуру или вспомогательныю память) virtual ~Shape(); // Метод setTexture, принимает 2 параметра, из которых 1 - необязательный. void setTexture(const Texture* texture, bool resetRect = false); // . >;
Что означает public перед именем базового типа? Во-первых внешний код может передать RectangleShape в функцию, принимающую ссылку на Shape, то есть возможен так называемы upcast от более низкого (и более конкретного) типа RectangleShape к более высокому (и более абстрактному) типу Shape:
// Хотя параметр имеет тип Shape, мы можем передать тип RectangleShape, // потому что RectangleShape является Shape. // Аналогично мы можем передать CircleShape. void drawShape(sf::RenderWindow& window, const Shape& shape) window.draw(shape); > // Параметр имеет тип RectangleShape, и передать Shape или CircleShape нельзя, // потому что ни Shape, ни CircleShape не являются RectangleShape. void drawRect(sf::RenderWindow& window, const RectangleShape& shape) window.draw(shape); >
Во-вторых из-за public наследования все унаследованные поля и методы сохраняют свой уровень доступ: приватные остаются приватными, публичные остаются публичными. А если бы мы наследовали Shape с ключевым словом private, то уровень доступа стал бы ниже: все методы и поля стали бы приватными:
// ! КОД НАМЕРЕННО УПРОЩЁН! // Все поля и методы Shape, даже публичные, стали приватными в RectangleShape class RectangleShape : private Shape public: RectangleShape(const Vector2f& size = Vector2f(0, 0)); void setSize(const Vector2f& size); >;
Контроль уровня доступа полей и методов — хитрый механизм, пройдёт немало времени, прежде чем вы научитесь пользоваться им правильно. В начале просто старайтесь сделать правильный выбор между private и public. Скорее всего поля будут private, а конструктор и все методы будут public. Это позволяет сохранять инвариант класса, то есть держать поля объекта в согласованном состоянии независимо от того, какие методы вызывают извне.
Основы полиморфизма: виртуальные методы и их перегрузка
SFML использует ещё одну идиому C++: виртуальные методы. Ключевые слова virtual , final , override относятся именно к этой идиоме. Например, в SFML определяется класс Drawable, который обозначает “сущность, которую можно нарисовать”. Все рисуемые классы SFML, включая sf::Sprite , sf::RectangleShape , sf::Text , прямо или косвенно наследуются от sf::Drawable .
// ! КОД НАМЕРЕННО УПРОЩЁН! class Drawable public: // Виртуальный деструктор. virtual ~Drawable() <> // Виртуальный метод draw virtual void draw(RenderTarget& target, RenderStates states) const; >;
Зачем это надо? Дело в том, что метод draw класса RenderWindow принимает параметр типа Drawable . Тем не менее, этот метод успешно рисует любые типы объектов: спрайты, фигуры, тексты. Он не выполняет проверок — он просто настраивает состояние рисования (RenderStates) и вызывает метод draw у сущности, которая является Drawable .
void RenderWindow::draw(const Drawable& drawable) RenderStates states = . ; // как-то настраиваем состояние. drawable.draw(*this, states); >
Виртуальный метод вызывается косвенно: если класс Shape , унаследованный от Drawable , переопределил метод, а потом был передан как параметр типа Drawable , то вызов метода draw всё равно приведёт к вызову переопределённого метода Shape::draw , а не метода Drawable::draw ! С обычными (не виртуальными) методами такого не происходит: если бы мы убрали слово virtual из объявления draw , то вызов метода draw у параметра типа Drawable всегда приводил бы к вызову Drawable::draw , даже если реальный тип объекта, скрытого за этим параметром, совсем другой.
Возможность по-разному реагировать на одинаковый вызов метода извне называется полиморфизмом. Точнее, это одна из разновидностей полиморфизма объектов.
Другими словами, RenderWindow и RectangleShape не знают, что они работают друг с другом, но тем не менее каждый вызывает правильный метод другого класса!

Когда вы просто вызываете window.draw(shape) , повышение класса происходит дважды: сначала конкретный класс фигуры повышается до более ограниченного класса Drawable, затем конкретный класс RenderWindow повышается до абстрактного RenderTarget. Всё это не требует времени при выполнении: просто компилятор выполняет проверки типов данных ещё при компиляции, не более того.
Как унаследовать Drawable: практический пример
Мы создадим класс, который рисует флаг России. Он будет унаследован от Drawable, чтобы использовать для рисования обычный метод draw у объекта окна.
#pragma once #include // Класс RussianFlag рисует флаг России. // Наследуем его от sf::Drawable, чтобы можно было рисовать флаг проще: // window.draw(flag); class RussianFlag : public sf::Drawable public: // Конструктор принимает два параметра: положение и размер флага. RussianFlag(const sf::Vector2f& position, const sf::Vector2f& size); private: // Метод draw вызывается окном при рисовании флага, // то есть window.draw(flag) косвенно привозит к вызову этого метода. void draw(sf::RenderTarget& target, sf::RenderStates states) const override; sf::RectangleShape m_whiteStrip; sf::RectangleShape m_blueStrip; sf::RectangleShape m_redStrip; >;
Теперь мы можем реализовать конструктор и метод draw. В конструкторе мы должны вычислить и установить позиции и размеры трёх полос на флаге, а в методе draw мы должны их последовательно нарисовать.
#include "RussianFlag.h" RussianFlag::RussianFlag(const sf::Vector2f& position, const sf::Vector2f& size) const sf::Vector2f stripSize = size.x, size.y / 3.f >; m_whiteStrip.setSize(stripSize); m_whiteStrip.setPosition(position); m_whiteStrip.setFillColor(sf::Color(0xFF, 0xFF, 0xFF)); m_blueStrip.setSize(stripSize); m_blueStrip.setPosition(position + sf::Vector2f 0.f, stripSize.y >); m_blueStrip.setFillColor(sf::Color(0, 0, 0xFF)); m_redStrip.setSize(stripSize); m_redStrip.setPosition(position + sf::Vector2f 0.f, 2.f * stripSize.y >); m_redStrip.setFillColor(sf::Color(0xFF, 0, 0)); > void RussianFlag::draw(sf::RenderTarget& target, sf::RenderStates states) const target.draw(m_whiteStrip, states); target.draw(m_blueStrip, states); target.draw(m_redStrip, states); >
Теперь использовать класс RussianFlag извне очень легко!
#include "RussianFlag.h" #include #include // Функция создаёт окно определённого размера с определённым заголовком. void initWindow(sf::RenderWindow& window) sf::VideoMode videoMode(800, 600); const std::string title = "Russian Flag + class derived from sf::Drawable"; sf::ContextSettings settings; settings.antialiasingLevel = 8; window.create(videoMode, title, sf::Style::Default, settings); > int main() sf::RenderWindow window; initWindow(window); RussianFlag flag(100, 50>, 300, 150>); while (window.isOpen()) sf::Event event; while (window.pollEvent(event)) if (event.type == sf::Event::Closed) window.close(); > > // Рисуем flag как обычную фигуру или спрайт: вызовом window.draw. window.clear(); window.draw(flag); window.display(); > >
PS-Group
- PS-Group
- sshambir@gmail.com
- ps-group
- image/svg+xml sshambir
