Справка по использованию нескольких заголовков и файлов cpp - PullRequest
0 голосов
/ 07 апреля 2011

Я создаю приложение с помощью DragonFireSDK и хочу организовать мое приложение из нескольких тысяч строк с файлами .cpp и .h

Я получаю тонны ошибок при попытке сделать что-то, хотя

Итак, мой app.cpp (основной, необходимый) выглядит следующим образом

Код:

#include "DragonFireSDK.h"

#include "SaveData.h"
#include "Structures.h"
#include "Definitions.h"
#include "Variables.h"
#include "SaveData.h"

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "Functions.cpp"
#include "AppMain.cpp"
#include "AppExit.cpp"
#include "OnTimer.cpp"

#include "SaveData.h" через #include "Variables.h" у всех есть что-то вроде Код:

#ifndef _HeaderName
#define _HeaderName
//STUFF HERE LIKE
#define player1 0
#define player2 1
//OR
typedef struct _number {
    int view;
    int number;
    bool able;
    int opacity;
};_number number[4];
//OR
int whoseturn;

int bet[5];
bool reachedmax[5];

int playerimg[5];
#endif

Теперь я, возможно, уже что-то делаю не так, но вот еще ... Мой AppMain.cpp, OnTimer.cpp и т. Д. Выглядит так (AppMain () и т. Д. Также являются обязательными функциями) Код:

#include "DragonFireSDK.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "Definitions.h"
#include "Structures.h"
#include "Variables.h"
#include "SaveData.h"

#include "Functions.cpp"

void AppMain() {
//STUFF HERE
};

Теперь я думаю, что здесь проблема ... Functions.cpp Код:

#include "DragonFireSDK.h"

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "SaveData.h"
#include "Structures.h"
#include "Definitions.h"
#include "Variables.h"
//SOME FUNCTIONS
void   SavePlayerMoney();
void   SetInfo            (int idnum, bool actuallyset = false);
void   SwitchButton       (int idnum, bool makeactive=true);
void   DisableButton      (int idnum);
double round              (double number);

void SavePlayerMoney() {
    //...
}
void   SetInfo(int idnum, bool actuallyset) {
      //...
}
void   SwitchButton(int idnum, bool makeactive) {
      //...
}
void   DisableButton(int idnum){
      //...
}

Теперь ошибки, которые я получаю после того, как подумали, если все исправлено ... Код:

1>AppMain.obj : error LNK2005: "void __cdecl SwitchButton(int,bool)" (?SwitchButton@@YAXH_N@Z) already defined in App.obj
1>AppMain.obj : error LNK2005: "double __cdecl round(double)" (?round@@YANN@Z) already defined in App.obj
1>AppMain.obj : error LNK2005: "void __cdecl SetInfo(int,bool)" (?SetInfo@@YAXH_N@Z) already defined in App.obj
1>AppMain.obj : error LNK2005: "int __cdecl Digits(int)" (?Digits@@YAHH@Z) already defined in App.obj

Любая помощь очень ценится!

Ответы [ 4 ]

3 голосов
/ 07 апреля 2011

Не #include .cpp файлы.

Модель компиляции C состоит в том, что каждая функция определяется только один раз, то есть ровно в одной единице компиляции (то есть в одном объектном файле).).Каждый исходный файл компилируется независимо в отдельный объектный файл (#include -ing header файлы, чтобы компилятор знал, например, прототип используемых функций).Затем вы связываете эти отдельные объектные файлы вместе, чтобы сформировать конечный исполняемый файл.

Если вы #include .cpp файлы, вы получите одну и ту же функцию: , определенную в нескольких блоках компиляции(помните, что #include в основном эквивалентно копированию и вставке содержимого в файл, который выполняет включение).Так что компоновщик запутается и выдаст вам сообщения, которые вы видите.

ОБНОВЛЕНИЕ

О, я вижу, проблема в том, что у вас нетсоответствующий заголовочный файл для Functions.cpp.Идея состоит в том, что вы также пишете Functions.h, в соответствии с:

#ifndef FUNCTIONS_H_
#define FUNCTIONS_H_

void SavePlayerMoney();
void SetInfo(int idnum, bool actuallyset);
void SwitchButton(int idnum, bool makeactive);
void DisableButton(int idnum);

#endif

И затем вы #include это заголовочный файл , а не файл .cpp.

2 голосов
/ 07 апреля 2011

Компоновщик жалуется, потому что функции определены более одного раза. Функция может быть определена только в одной единице перевода (файл cpp, после компиляции она становится файлом obj) - за исключением случаев, когда она объявлена ​​inline.

Вы включаете Functions.cpp в другие модули, поэтому определения функций из Function.cpp дублируются в них, вызывая проблемы с компоновщиком.

Решением было бы объявить функции inline - или, что еще лучше, объявить их в заголовке (то есть Functions.h) и определить их в Functions.cpp , Любые пользователи этих функций могут затем #include Functions.h и иметь доступ к этим функциям, даже если они не знают о своей реализации.

Чтобы объявить функцию, выполните: int foo();, фактически определите это, выполните int foo() { your code goes here}.

1 голос
/ 07 апреля 2011

Я думаю, что все очень хорошо ответили на этот вопрос, поэтому я просто собираюсь рассказать вам о своей философии C ++ в отношении больших проектов, потому что кажется, что это информация, которую вы можете найти полезной.

ВСЕГДА отдельные объявления функций и их реализация. Это значительно облегчит вашу жизнь. Объявите прототипы функций в файле .h, затем запишите реализацию в файле .cpp.

Например:

// mystuff.h
#ifndef MYSTUFF_H
#define MYSTUFF_H

int myFunction(int value, char letter);

#endif

И в моем .cpp файле:

// mystuff.cpp

#include "mystuff.h"

int myFunction(int value, char letter) {
    // insert implementation here
}

Зачем это? Хорошо, одна веская причина в том, что когда ваш код не работает (как это, якобы, будет неизбежной реальностью для любого программиста), вы можете заменить ваш файл .cpp альтернативными реализациями, не изменяя структуру вашего кода. Мало того, вы обнаружите различные уловки, которые будут опираться на разделение деклараций и реализации, которые значительно облегчат вашу жизнь. Итог, сделай это.

Попытка инкапсуляции везде, где это возможно. Если вы делаете большой проект (и вы заметите, что это верно для большинства крупных проектов, с которыми вы сталкиваетесь), инкапсуляция похожих функций, переменных и тому подобного сэкономит вам значительное время и энергию. Похоже, что вы создаете программу для игры - вы думали о том, чтобы заключить каждого игрока в класс Player или Human, со специфическими для каждого класса функциями? Если вы являетесь наркоманом C ++ или Java, как я, вы обнаружите, что объектно-ориентированный подход является наиболее эффективным подходом в 99 случаях из 100 (в 1% случаев обычно используются вспомогательные функции, которые на самом деле не подходят в любом из объектов, которые вы определили).

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

Очевидно, это моя собственная философия, а не та, которую я хотел бы принудительно навязать вам. Но, надеюсь, вы воспользуетесь несколькими полезными советами из моего краткого бреда, чтобы улучшить способ написания кода и / или избежать длинных списков ошибок. Желаем удачи!

1 голос
/ 07 апреля 2011

Переместите объявления функций в заголовочные файлы. Например, похоже, что Functions.h должен содержать:

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

//SOME FUNCTIONS
void   SavePlayerMoney();
void   SetInfo            (int idnum, bool actuallyset = false);
void   SwitchButton       (int idnum, bool makeactive=true);
void   DisableButton      (int idnum);
double round              (double number);

#endif

Тогда Functions.cpp может просто включать Functions.h вместо этих объявлений. Некоторые заголовочные файлы могут включать другие заголовочные файлы, чтобы получить соответствующие типы.

Наконец, никогда #include файл * .cpp.

...