Ok, so I have a struct defined as thus:
#ifndef __STRUCTS_H__
#define __STRUCTS_H__
struct counts {
int views = 0;
int inits = 0;
};
#endif
I have a class that is going to have entirely static methods and variables that are accesable by all classes.
#ifndef __HOLDER_H__
#define __HOLDER_H__
#include "Structs.h"
class Holder
{
public:
static counts menus;
Holder() {
menus = counts();
}
};
#endif
And so I tried to acess this method and the compiler spits out the error "Undefined reference to Holder::menus"
Here is the segment that triggers this (HelloWorldScene.cpp)
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
#include "Holder.h"
#include "Structs.h"
USING_NS_CC;
HelloWorld::HelloWorld(void)
{
//Constructor
Debug::crashLog("**__Menu Deinit__**");
//SUDO Missing stuff
Holder::menus.inits -= 1;
}
Why is it having issues?
in your Holder implementation file you need this:
counts Holder::menus;
if you don't have Holder.cpp file, (and you don't want one) you can put it directly into in HelloWorldScene.cpp.
Related
Ok, so before you all go pointing me to the different posts where this question has already been addressed, I wish to disclaim that I have indeed solved my issue following this post here.
This post is more about digging beneath the surface of how the compiler works.
Here we go...
Menu.h includes MenuEntry.h and MenuEntryKey.h, like so:
#ifndef MENU_H
#define MENU_H
#include <cstdlib>
#include <map>
#include <string>
#include "MenuEntry.h"
#include "MenuEntryKey.h"
class Menu
{
public:
// ctor, dtor, copy control
Menu(const std::map<MenuEntryKey, MenuEntry> &opts = std::map<MenuEntryKey, MenuEntry>(),
const unsigned numF = 0, const unsigned numD = 0) : options_(opts),
numFoodOptions_(numF),
numDrinkOptions_(numD) {}
~Menu() {}
Menu(const Menu &);
Menu &operator=(const Menu &);
// entry select funcs: both simply return a random menu selection's name, based on the provided entry type.
inline const std::string selectOption(const char);
private:
const std::map<MenuEntryKey, MenuEntry> options_;
const unsigned numFoodOptions_;
const unsigned numDrinkOptions_;
// private accessors; Guests must only be able to select a valid option. This can be changed later, if need be.
inline const std::map<MenuEntryKey, MenuEntry> &getOptions() const { return options_; }
inline const std::map<MenuEntryKey, MenuEntry> &getOptions()
{
return (static_cast<const Menu &>(*this)).getOptions();
}
inline const unsigned getNumFoodOptions() const { return numFoodOptions_; }
inline const unsigned getNumDrinkOptions() const { return numDrinkOptions_; }
};
#endif // MENU_H
Showing you MenuEntry.h and MenuEntryKey.h is really not relevant to this question; they are both just standalone components used to build the Menu.
Next, I have a class called DataLoader, which creates a Menu based on plaintext metadata. Here is DataLoader.h:
#ifndef DATALOADER_H
#define DATALOADER_H
#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include <ctype.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include "Menu.h"
#include "MenuEntryKey.h"
#include "MenuEntry.h"
class Menu;
namespace DataLoader
{
const Menu &createMenu();
} // namespace DataLoader
#endif // DATALOADER_H
As it stands, there are no errors in DataLoader.cpp; however, as soon as I remove the MenuEntry.h and MenuEntryKey.h includes from DataLoader.h, like so:
#ifndef DATALOADER_H
#define DATALOADER_H
#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include <ctype.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include "Menu.h"
// Note the missing includes that used to be here.
// "" ""
class Menu;
namespace DataLoader
{
const Menu &createMenu();
} // namespace DataLoader
#endif // DATALOADER_H
I get incomplete type is not allowed (DataLoader.cpp):
#include "DataLoader.h"
const Menu &DataLoader::createMenu()
{
std::ifstream in;
in.open("../../../../meta/menu.md");
if (!in)
{
std::cout << "Unable to open file.\n";
exit(-1);
}
std::map<MenuEntryKey, MenuEntry> options;
std::string line;
while (std::getline(in, line))
{
if (line.size() == 0)
continue;
if (line[0] == '-')
{
char entryType = toupper(line[1]);
unsigned num = 0;
std::vector<std::string> tokens;
std::getline(in, line);
while (line[0] != '^')
{
boost::algorithm::split(tokens, line, boost::algorithm::is_any_of(" "));
MenuEntryKey key; //INCOMPLETE TYPE ERROR HERE
}
}
} // end while
}
The reason this is so baffling to me is Menu.h includes MenuEntry.h and MenuEntryKey.h! Would that not imply that including Menu.h would also include the latter two? Please enlighten me on this strange occurrence.
The reason I DON'T want to include MenuEntry.h and MenuEntryKey.h in DataLoader.h is because I have learned it is generally a good practice to avoid including things that have already been included, which is something I am currently trying to get a better grip on.
Note that if you look at my headers closely, you'll see that I double include some STL headers, which was no accident; I just have yet to find and integrate a clean method of taking care of it.
Let me know if you need more information. Hopefully, this question is appropriate for SO and I have provided enough detail.
Cheers
EDIT:
I am seeing a little bit of confusion in the comments, so I am going to try to clarify my question as best as I can.
• Menu.h includes BOTH MenuEntry.h and MenuEntryKey.h.
• MenuEntry.h only includes and MenuEntryKey.h includes literally nothing. AFAIK, There are no circular dependencies between Menu.h, MenuEntry.h, and MenuEntryKey.h.
• When DataLoader.cpp includes ONLY Menu.h, the preprocessor cannot find a complete definition for MenuEntryKey.h OR MenuEntry.h, even though both of these files are included by Menu.h.
If including works similarly to copying and pasting code, then why can't the preprocessor find complete definitions for MenuEntry and MenuEntryKey in DataLoader.cpp? Shouldn't including Menu.h copy and paste the code from that header, which in turn, copies and pastes the headers MenuEntry.h and MenuEntryKey.h???
Hope this helps.
As requested, I will provide a basic working example of what I am talking about. Please give me 5 minutes.
EDIT #2:
Here is your minimal reproducible example.
MenuEntryKey.h:
#ifndef MENUENTRYKEY_H
#define MENUENTRYKEY_H
class MenuEntryKey
{
public:
MenuEntryKey(char type = '!', unsigned num = 0) : type_(type), num_(num) {}
private:
const char type_;
const unsigned num_;
};
#endif // MENUENTRYKEY_H
MenuEntry.h:
#ifndef MENUENTRY_H
#define MENUENTRY_H
#include <string>
class MenuEntry
{
const std::string name_;
};
#endif // MENUENTRY_H
Menu.h:
#ifndef MENU_H
#define MENU_H
#include "MenuEntry.h"
#include "MenuEntryKey.h"
class Menu
{
public:
private:
const unsigned numFoodOptions_;
const unsigned numDrinkOptions_;
};
#endif // MENU_H
DataLoader.h:
#ifndef DATALOADER_H
#define DATALOADER_H
class Menu;
namespace DataLoader
{
const Menu &createMenu();
} // namespace DataLoader
#endif // DATALOADER_H
DataLoader.cpp:
#include "DataLoader.h"
#include "Menu.h"
// #include "MenuEntry.h"
// #include "MenuEntryKey.h"
const Menu &DataLoader::createMenu()
{
MenuEntryKey key;
}
Amazingly enough, this skeleton example produces no incomplete type error. Note the two include statements that are commented out.
Why would this work now, when before it didn't? It must have something to do with included headers; could STL header includes cause this, or only includes of user-defined headers? Would include guards stop this from happening?
Thanks for all your help, I really appreciate it.
I have three files in the following structure
- src/
- events
- ...
- Event.cpp
- Event.h
- EventPtr.h
- ...
The issue is that the #include Event.h inside EventPtr.h doesn't seem to be working. Here is the code:
Event.h
#ifndef POKERSIMULATIONSINCPP_EVENT_H
#define POKERSIMULATIONSINCPP_EVENT_H
#include <iostream>
#include "game/Table.h"
#include "players/Player.h"
namespace events {
enum TargetType {
Dealer, Table, None, Players
};
class Event {
private:
TargetType target = None;
std::string description = "Base event class";
bool done = false;
public:
~Event();
Event();
TargetType getTarget();
std::string getDescription();
bool getDone();
};
}
#endif //POKERSIMULATIONSINCPP_EVENT_H
Event.cpp
#include "Event.h"
#include <iostream>
namespace events {
TargetType Event::getTarget() {
return target;
}
std::string Event::getDescription() {
return description;
}
bool Event::getDone() {
return done;
}
Event::~Event() = default;
Event::Event() = default;
}
EventPtr.h
#ifndef POKERSIMULATIONSINCPP_EVENTPTR_H
#define POKERSIMULATIONSINCPP_EVENTPTR_H
#include <memory>
#include "events/Event.h"
namespace events {
typedef std::shared_ptr<Event> EventPtr;
}
#endif //POKERSIMULATIONSINCPP_EVENTPTR_H
Which gives the following error:
The Error
D:/PokerSimulationsInCpp/src/events/EventPtr.h:13:29: error: 'Event' was not declared in this scope
typedef std::shared_ptr<Event> EventPtr;
I've also tried this for EventPtr.h
EventPtr.h, second try
#ifndef POKERSIMULATIONSINCPP_EVENTPTR_H
#define POKERSIMULATIONSINCPP_EVENTPTR_H
#include <memory>
#include "events/Event.h"
#include "Event.h"
namespace events {
typedef std::shared_ptr<events::Event> EventPtr;
}
#endif //POKERSIMULATIONSINCPP_EVENTPTR_H
Which gives the following error:
D:/PokerSimulationsInCpp/src/events/EventPtr.h:14:37: error: 'Event' is not a member of 'events'
typedef std::shared_ptr<events::Event> EventPtr;
Anybody know what is going on?
Probably you have a circular include dependencies.
Please Check the file included by Event.h . If you find EventPtr.h included this could be the error.
I leave you a wikipedia link on this : Circular Dependency
I've created 2 header files. ListA.h and ListN.h
They both make their own use their own unique class List. When I compile my program (even though they have no way of knowing the other exists, it says the following error)
Im pretty sure it shouldnt be a redefinition, but it obviously is. Any help is appreciated.
ListA.h
#ifndef __LISTA_H_
#define __LISTA_H_
#include <iostream>
using namespace std;
class List{
public:
List(int = 0);
List(const List&);
~List();
};
#endif
ListN.h
#ifndef __LISTN_H_
#define __LISTN_H_
#include <iostream>
using namespace std;
class List{
public:
List(int = 10);
List(const List&);
~List();
};
#endif
ListA.cpp
#include "ListA.h"
using namespace std;
List::List(int mySize)
{
//...
}
ListN.cpp
#include "ListN.h"
#include <iostream>
using namespace std;
List::List(int size)
{
//...
}
Main
#include <iostream>
#include "ListN.h"
using namespace std;
int main()
{
List myList;
return 0;
}
Both cpp files are being compiled by the compiler. Thus, when the linker goes to link the files together, it gets confused, since there are multiple List classes.
To fix this, you could use namespaces, or you cold not expose at least one of the List classes.
Alternatively, if the idea was to be able to include ListN.h vs ListA.h for configuration purposes, this is the wrong way to do so. Either you should have a #define parameter for the header, or you should find some other way, such as through #ifdef. For example (I'm not 100% sure this would compile, but you get the idea):
List.h
#ifndef __LIST_H_
#define __LIST_H_
#ifndef LIST_PARAM
#define LIST_PARAM 0
#endif
#include <iostream>
using namespace std;
class List{
public:
List(int = LIST_PARAM);
List(const List&);
~List();
};
#endif
main.cpp
#include <iostream>
#define LIST_PARAM 10
#include "List.h"
using namespace std;
int main()
{
List myList;
return 0;
}
I personally don't like this method; it is much better to just pass the value in to the constructor:
int main()
{
List myList{ 10 };
return 0;
}
When linker trying to link find the definition / symbol for List, it does found in two different obj file and hence linker givers error. In visual studio error number : LNK2005
To solve this error, either:
To fix, add /FORCE:MULTIPLE to the linker command line options
Add the classes in two different namespaces which will avoid this error.
ListN.h
#ifndef __LIST_H_
#define __LIST_H_
#include <iostream>
using namespace std;
namespace ListN
{
class List{
public:
List(int = 10);
List(const List&);
};
}
#endif
ListN.cpp
#include "ListN.h"
#include <iostream>
using namespace std;
namespace ListN
{
List::List(int size)
{
//...
}
}
Main.cpp
#include <iostream>
#include "ListN.h"
int main()
{
ListN::List myList;
return 0;
}
I got three .cpp files and two header files.
But when i compile them, meaning the Point.cpp, Data.cpp and main.cpp, it will say
Data.h:6:7 redefinition of Data at 'Data.h'
Data.h:6:7 previously definition of 'class Data'
Below is my Data.h(previously known as 2.h at above)
#include <iostream>
#include <string>
using namespace std;
class Data
{
private:
string sType;
public:
Data();
Data(string);
void setSType(string);
string getSType();
};
Below is my data.cpp
#include "Data.h"
Data::Data()
{
sType = "";
}
Data::Data(string s)
{
sType = s;
}
void Data::setSType(string ss)
{
sType = ss;
}
string Data::getSType()
{
return sType;
}
Below is my PointD.h (previously known as 3.h)
#include <iostream>
#include <string>
#include "Data.h"
using namespace std;
class PointD
{
private:
int x
Data data1;
public:
PointD();
PointD(int,Data);
void setX(int);
void setData(Data);
int getX();
Data getData();
};
Below is my PointD.cpp
#include "PointD.h"
PointD::PointD()
{
x = 0;
}
PointD::PointD(int xOrdinate,Data dd)
{
x = xOrdinate;
data1 = dd;
}
void PointD::setXordinate(int Xordinate)
{
x = Xordinate;
}
void PointD::setData(Data dd)
{
data1 = dd;
};
int PointD::getXordinate()
{
return x;
}
Data PointD::getData()
{
return data1;
}
This is my main.cpp
#include <iostream>
#include <string>
#include "Data.h"
#include "PointD.h"
using namespace std;
int main()
{
const int MAX_NUM = 20;
Data ldata[MAX_NUM];
PointD pointd[MAX_NUM];
//more codes..
}
But when i compile them, meaning the Point.cpp, Data.cpp and main.cpp, it will say
Data.h:6:7 redefinition of Data at 'Data.h'
Data.h:6:7 previously definition of 'class Data'
Can anybody let me know whats actually went wrong here..
You need to use include guards, or the easiest:
#pragma once
in your header files
See Purpose of Header guards for more background
Idea: 1.hpp
#ifndef HEADER_GUARD_H1_HPP__
#define HEADER_GUARD_H1_HPP__
// proceed to declare ClassOne
#endif // HEADER_GUARD_H1_HPP__
In each of your header files write:
#ifndef MYHEADERNAME_H
#define MYHEADERNAME_H
code goes here....
#endif
Its better like this:
#ifndef DATA_H /* Added */
#define DATA_H /* Added */
#include <iostream>
#include <string>
// using namespace std; /* Removed */
class Data
{
private:
std::string sType;
public:
Data();
Data( std::string const& ); // Prevent copy of string object.
void setSType( std::string& ); // Prevent copy of string object.
std::string const& getSType() const; // prevent copy on return
std::string& getSType(); // prevent copy on return
};
#endif /* DATA_H */
The big fix is adding ifndef,define,endif. The #include directive works as if copying and pasting the .h to that line. In your case the include from main.cpp are:
main.cpp
-> Data.h (1)
-> Point.h
-> Data.h (2)
At (2), Data.h has already been `pasted' into main.cpp at (1). The class declaration of Data, i.e. "class Data{ .... };" , appears twice. This is an error.
Adding include guards to the top and bottom of every .h are standard practice to avoid this problem. Don't think about it. Just do it.
Another change I'd suggest is to remove any "using namespace ..." lines from any .h . This breaks the purpose of namespaces, which is to place names into separate groups so that they are not ambiguous in cases where someone else wants an object or function with the same name. This is not an error in your program, but is an error waiting to happen.
For example, if we have:
xstring.h:
namespace xnames
{
class string
{
...
};
}
Foo.h
#include <xstring>
using namespace xnames;
...
test.cxx:
#include "Foo.h"
#include "Data.h" // Breaks at: Data( string ); -- std::string or xnames::string?
...
void test()
{
string x; // Breaks. // std::string or xnames::string?
}
Here the compiler no longer knows whether you mean xnames::string or std::string. This fails in test.cxx, which is fixable by being more specific:
void test()
{
std::string x;
}
However, this compilation still now breaks in Data.h. Therefore, if you provide that header file to someone, there will be cases when it is incompatible with their code and only fixable by changing your header files and removing the "using namespace ...;" lines.
Again, this is just good coding style. Don't think about it. Just do it.
Also, in my version of Data.h, I've changed the method parameters and return types to be references (with the &). This prevents the object and all of its state from being copied. Some clever-clogs will point our that the string class's is implementation prevents this by being copy-on-write. Maybe so, but in general, use references when passing or returning objects. It just better coding style. Get in the habit of doing it.
Recently I've been learning how to create methods within classes so that I only have to write a method once and for each of that class I instantiate I can call the one method and it will work only on the variables of the object that called it, I know how to do this when only using main.cpp and no headers however I am confused on how I should be writing this when I use a class header and cpp.
I have a sample of code similar to what I want to achieve:
#include <iostream>
using namespace::std;
class Object
{
public:
int stuff;
void manageStuff();
Object();
};
void Object::manageStuff()
{
stuff++;
}
Object::Object() : stuff(0) {}
Object object1, object2;
int main() {
for (int i = 0; i < 10; i++)
{
object1.manageStuff();
object2.manageStuff();
cout << object1.stuff << "\n";
cout << object2.stuff << "\n";
}
}
This works fine and allows me to have two instances of Object and a method that works independently for each instance, this is my current project:
main.cpp:
#include <iostream>
#include "Test.h"
using namespace std;
int main()
{
Test test;
for (int i = 0; i < 10; i++)
{
test.count(); // Here's my error "undefined reference to Test::count"
}
return 0;
}
Test.cpp
#include <iostream>
#include "Test.h"
using namespace std;
Test::Test()
{
//ctor
}
Test::~Test()
{
//dtor
}
Test.h
#include <iostream>
#ifndef TEST_H
#define TEST_H
class Test
{
public:
Test();
virtual ~Test();
void count();
int counter();
};
#endif // TEST_H
and finally TestFunctions.h
#include <iostream>
#include "Test.h"
#ifndef TESTFUNCTIONS_H_INCLUDED
#define TESTFUNCTIONS_H_INCLUDED
void Test::count()
{
Test::counter++;
std::cout << Test::counter;
}
#endif // TESTFUNCTIONS_H_INCLUDED
I'm sure that there will be something that's very obviously wrong to a more seasoned programmer and I'm about to look a bit thick but any help would be greatly appreciated
Thanks!
I would suggest getting rid of TestFunctions.h, and adding the implementation of Test::count() to Test.cpp. Currently, the TestFunctions.h header is not included anywhere, so you have no access to the definition from main.
You defined (i.e. implemented) Test::count() in a header file (TestFunctions.h), but you never included it anywhere so the code there is not compiled.
You should change it to be in a .cpp file, compile it and link it with the other source files. There's no reason why not to place it in Test.cpp.
Rename TestFunctions.h into TestFunctions.cpp, make it compiled same way as main.cpp and linked.
Alternatively, include TestFunctions.h somewhere, e.g. main.cpp