My searches have lead me to believe that the problem I am experiencing is called cyclic redundancy. I don't understand any of the solutions that are posted. I am (fairly) new to C++, coming from a strong Java background.
Basically there are two classes that depend on each other. Class A contains a vector of class B objects, and class B contains methods that require class A objects as input.
Here's code that reproduces the problem.
According to codelite g++, the error is in school.h and is "person was not declared in this scope". It also says "template argument 1 is invalid" and "template argument number 2 is invalid". Then a couple of others, about non-class type "int" on all the vector functions that get invoked.
main.cpp
#include <iostream>
#include <string>
#include "person.h"
#include "school.h"
int main() {
person p;
school s;
std::cout << p.name << std::endl;
s.personVect.push_back(p);
std::cout << s.personVect.size() << std::endl;
std::cout << s.personVect.at(0).name << std::endl;
p.test();
return 0;
}
school.h
#ifndef SCHOOL_H
#define SCHOOL_H
#include <vector>
#include "person.h"
class school
{
public:
school();
~school();
std::vector<person> personVect;
};
#endif // SCHOOL_H
school.cpp
#include "school.h"
school::school(){}
school::~school(){}
person.h
#ifndef PERSON_H
#define PERSON_H
#include <string>
#include <vector>
#include "school.h"
class person {
public:
std::string name;
std::string phone;
school doSomethingWithSchool();
void test();
person();
~person();
};
#endif // PERSON_H
person.cpp
#include "person.h"
#include <iostream>
using namespace std;
person::person()
{
name = "marcus";
phone = "0400000000";
}
person::~person()
{
}
void person::test() {
cout << this->name;
}
school person::doSomethingWithSchool() {
school s;
}
The problem can be resolved by designing you class relationships better.
A Person isn't composed of a School, so it doesn't need to have a School member.
A School has a collection of Person objects.
If you want a person to do something with a school, pass it as an argument. This way you can use pointers and forward declarations to solve the issue.
// Person.h
class School; // Forward declare school type.
// Person.cpp
Person::DoSomethingWithSchool(School* school);
Your issue is with the fact that school.h has an #include "person.h" statement, and person.h has an #include "school.h" statement.
The solution
In the school class, instead of vector<person>, use vector<person*>. Instead of including person.h here, add the statement class person;. Assuming that your school class is eventually going to modify person objects somehow, put the #include person.h in your school.cpp file, after the statement #include school.h.
The error explained
This is a step-by-step breakdown of what happens when compiling:
In main.cpp, you first include person.h. The preprocessor goes and finds person.h. Since you've never included it before, PERSON_H has not yet been defined and the ifndef PERSON_H is currently true. So we go to the next line in the file.
The first interesting thing that happens in this file is that PERSON_H gets defined (#fdefine PERSON_H). The next time you #include this file, the preprocessor is going to skip the whole file, right to the #endif.
The second interesting thing to happen is that school.h gets included. So the preprocessor finds school.h (we haven't yet processed the School class!), which until now has never been processed.
The first interesting thing in school.h (after the #define SCHOOL_H) is the #include person.h, so the preprocessor returns to person.h (we haven't yet processed the Person class either!). But this time, PERSON_H is already defined, so #ifndef PERSON_H is false, and the preprocessor skips to the #endif in that file (as I mentioned in (2)). So the Person class still hasn't been declared.
We return to school.h, having done nothing. At this point, we are just about to declare/define the school class. The person class has never been declared because our preprocessor jumped from person.h to school.h back to person.h back to school.h, only processing #include directives.
The compiler starts going through the school class definition. The next interesting thing is the line std::vector<person> personVect;. You have tried to instantiate a vector<person>. But person here is unknown (i.e. has not been declared in this scope) because of (5). This explains your two template argument errors: A vector<person> is actually implicitly a vector <person, allocator<person> >. The first template argument is person and the second is allocator<person>. Since person is unknown, both these arguments are invalid.
The solution explained
The fact that school.h includes person.h, and person.h includes school.h, is what causes the cyclic dependency that you alluded to. To avoid this, we need an alternative way to declare that we are going to be using a particular class in a file. The common approach is to use a forward declaration - the statement class person; that I mentioned in the solution, before the definition of school. This is an ordinary declaration that lets the compiler know that person (as used in the school class) refers to a class.
However, in order to construct vector<person>, the compiler also needs to know how much space the class person occupies in memory (i.e. its size), which we aren't providing (and could never manually provide) with the declaration class person;. In fact, the compiler only knows the size of a class once the full definition in the header file has been processed. But if we try to do that, we're back to square one (cyclic dependency, and what not). What we do know is the size of a pointer to person, since that's machine specific (e.g. on a 32-bit machine, the size of a pointer to anything is 32 bits). Hence, we can instantiate a vector<person*> since this is always a vector of 32-bit objects regardless of what person actually is.
Try this,
person.h
#ifndef PERSON_H
#define PERSON_H
#include <string>
#include <vector>
class school;
class person {
public:
std::string name;
std::string phone;
school doSomethingWithSchool();
void test();
person();
~person();
};
#endif // PERSON_H
school.h
#ifndef SCHOOL_H
#define SCHOOL_H
#include <vector>
class person;
class school
{
public:
school();
~school();
std::vector<person*> personVect;
};
#endif // SCHOOL_H
person.cpp
#include "person.h"
#include "school.h"
#include <iostream>
using namespace std;
person::person()
{
name = "marcus";
phone = "0400000000";
}
person::~person()
{
}
void person::test() {
cout << this->name;
}
school person::doSomethingWithSchool() {
school s;
return s;
}
and in main.cpp
int main()
{
person *p = new person;
school s;
std::cout << p->name << std::endl;
s.personVect.push_back(p);
std::cout << s.personVect.size() << std::endl;
std::cout << s.personVect.at(0)->name << std::endl;
p->test();
delete p;
return 0;
}
Instead of including person #include "person.h"
In header file ("school.h") just write class person; and use pointer to person
And in c++ module ("school.cpp") include "person.h" if you need.
This will also have some benefits in feature. (reduce compilation time)
Useful links:
http://www.codeproject.com/Articles/547275/Whyplusisplusitplusbuildingplussopluslong-3f
https://stackoverflow.com/a/553869/328260
Related
I'm trying to finish a C++ school assignment and I have a question that I have an issue that may be simple. I have constructed all the files (more than below which felt was unnecessary to add) from scratch and I am left scratching my head. I'm told to create a private dynamic array of objects that will be defined by user input. This will be in the "student.cpp" file. This dynamic array is to create the objects that will operate the "course.cpp" file. I have attempted a large series of workarounds, but have not found the answer and expect the answer to be obvious. Here is the trimmed down version of my code. I also commented where the issue is in the student.cpp file and the other points of possible issue.
Any suggestions will be appreciated. I manually typed this again, so if it appears there was a typo, my apologies in advance. I will edit if I notice anything after the initial post.
//source.cpp
#include <iostream>
#include "student.h"
using namespace std;
void main() {
student stu;
stu.printRecord();
}
//student.h
#ifndef STUDENT_H
#define STUDENT_H
#include<iostream>
#include<string>
#include "course.h"
using namespace std;
class student{
public:
student();
void printRecord();
~student();
private:
string name;
int numCourses;
course* stuCourses; //possible source of error
};
#endif
//student.cpp
#include "student.h"
student::student(){
cout << "enter name: ";
getline(cin,name);
cout << "Enter the number of courses the student is taking: ";
cin >> numCourses;
course* stuCourses= new course[numCourses]; //possible source of error (now this->stuCourses = new course[numCourses];)
}
void student::printRecord(){
cout << endl << name << endl;
course::printCourse(); //Error at this point
}
//course.h
#ifndef COURSE_H
#define COURSE_H
#include <iostream>
using namespace std;
class course{
public:
course();
void printCourse();
~course();
private:
string title;
};
#endif
//course.cpp
#include <iostream>
#include "course.h"
course::course(){
cout << "Title: ";
cin >> title;
}
void course::printCourse(){
cout <<title;
}
course::~course(){}
Again, any help is appreciated. Thanks for looking even if you don't respond.
class course{
public:
course();
void printCourse();
~course();
private:
string title;
};
Here you defined printCourse as a non-static-method of the class course.
But where the error occurs: course::printCourse() you're trying to execute a static method of the class Course. If you don't know what I'm talking about here is a short summary (but i recommend reading about the differences between static and non static methods):
A static method works without an instance of the class. This is commonly used on singletons which are by design "just one single object". This could be for example a global ID-Counter for the students:
class StudentIdManager
{
static int num_students = 0;
public:
static int getNextStudentId()
{
return num_students++;
}
}
You can now get the next unique id for a student by calling StudentIdManager::getNextStudentId() without an actual object. You could call it a "class function". Not an "object function".
A static class is obviously not suitable for your course, so it makes sense for your to implement it like you did.
However, you have to call it on an actual object. The difficulty is to find each object in the dynamically allocated array, but you should have every info you need. In the end it would look something like this:
void student::printRecord()
{
cout << endl << name << endl;
for (size_t i = 0u; i < numCourses; i++)
{
// here you're now calling the method printCourse on an actual course as intended instead of a static class
stuCourses[i]->printCourse();
}
}
However I also find it weird that you have to implement this. A simple std::array<course, numCorses> for a fixed number of courses, or a std::vector<course> for a variable number of courses would make the code way more readable, safe and extensible.
What you're doing here would is a nice task for C to get used to the Von Neuman Architecture.
But not for C++. It's not the same. Sadly for most teachers C++ is "C with classes" which is just wrong on so many levels. All the features C++ added where there for you to not write code like your teacher wants.
Instead of:
course* stuCourses= new course[numCourses];
Can use:
this->stuCourses = new course[numCourses];
Or even:
stuCourses = new course[numCourses];
First I'm a beginner at programming so don't expect me to understand every code-specific word.
Second I'm sometimes slow on the uptake.
Third I think I covered the Basics of C++ but that's it. I'm happy to learn more of course!
To my Question:
I'm programming a little code to experience with classes. I made two classes, each one in a different .h and .cpp file. Now each one is using the headers iostream and string.
How should I include those without making any Problems? Is #pragma once sufficient?
Second question is about using namespace std:
where should i put it(I know it isn't a bad use but ist only for a small Programm)
First Header:
#pragma once
#include <iostream>
#include <string>
//using namespace std Nr.1
class one
{
};
Second Header:
#pragma once
#include <iostream>
#include <string>
//using namespace std Nr.2
class two
{
};
Finally Main:
#include "one.h"
#include "two.h"
//using namespace std Nr.3
int main()
{
return 1;
};
Thanks in advance for responding.
There's no problem including twice iostream and string in both class headers'.
The #pragma directive is used to protect two declarations of types (typedef, classes) of your own types.
Hence it applies to your class headers'.
Moreover, there are drawbacks using #pragma directive as stated here : https://stackoverflow.com/a/1946730/8438363
I recommend using preprocessor defines guards :
#ifndef __MY_HEADER__
#define __MY_HEADER__
//... your code here
#endif
Hope this helps.
You will need to use Include guards.They ensure the compiler includes each "included" header file(#include "XXX.h") only Once.
But if you are creating a small application & don't mind recompiling/rebuilding your entire project if need be, then putting the common header files in a dedicated header file is fair game & keeps code clean & small.
You can also make a header with all the common dependecies you need and include it in each class that needs those dependecies. Here is a simple example:
Core.h
#include <iostream>
#include <string>
// include most common headers
using namespace std;
One.h
#pragma once
#include "Core.h"
// if you need a header only for this class, put it here
// if you need a header in mutiple classes, put in Core.h
namespace one {
class One
{
public:
One();
~One();
void sumFromFirstNamespace(string firsNumber, string secondNumber)
{
//convert string to int
int first = stoi(firsNumber);
int second = stoi(secondNumber);
int result = first + second;
cout << result << endl;
}
};
}
Two.h
#pragma once
#include "Core.h"
// if you need a header only for this class, put it here
// if you need a header in mutiple classes, put in Core.h
namespace two{
class Two
{
public:
Two();
~Two();
void sumFromSecondtNamespace(string firsNumber, string secondNumber)
{
//convert string to int
int first = stoi(firsNumber);
int second = stoi(secondNumber);
int result = first + second;
cout << result << endl;
}
};
}
main.cpp
#include "One.h"
#include "Two.h"
int main()
{
one::One firstClass;
two::Two secondClass;
firstClass.sumFromFirstNamespace("10", "20");
secondClass.sumFromSecondtNamespace("20", "30");
}
There can be cases where you need the same 10+ headers in two different classes, i think that puting them in one header helps you see the code better.
And yes, preprocesor defines are also good, don't forget that. (:
I'm running into a lot of problems with this, primarily being that my passed Vector of my Class keeps getting flagged as an undeclared identifier. Any help on solving the problem or explanations to help me figure out what I don't understand would be greatly appreciated.
So here is a simplified version of what I have now:
main.cpp
#include "functions.h"
#include "vehicle.h"
int main()
{
int menuSelection;
vector<Vehicle> inventory;
do
{
cout << "Please make a selection:" << endl << endl;
cout << "1: Display Inventory" << endl;
.......
cout << "8 : Write inventory to file and exit" << endl << endl;
if (menuSelection == 1)
{
if (inventory.empty())
cout << "Database empty" << endl;
else
display(inventory);
.......
} while (menuSelection != 8);
return 0;
}
vehicle.h
#pragma once
#include "functions.h"
class Vehicle
{
private:
string VIN;
int year;
.......
// public:
// string getVIN();
.......
}
functions.h
#pragma once
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void display(vector<Vehicle>);
.......
void display(vector<Vehicle>& in)
{
Vehicle v;
cout << "VIN: " << v.getVIN(in)
}
.......
I've tried a bunch of different things to get it to work so that's why a lot of stuff may seem like odd syntax (I'm also not very good). My assignment is to have a menu in main.cpp which will create a vector from a class stored in vehicle.h, and then the menu is supposed to call functions which are located in functions.h that will communicate through vehicle.h to a fourth not included vehicle.cpp to work with information from the class.
In functions.h, void display(vector<Vehicle>); does not compile because Vehicle is undeclared at this point.
Also, in functions.h, void display(vector<Vehicle>& in) is a different overload to the previous prototype (the & makes a difference), probably not what you intended. And then you place a function body in functions.h -- this should not be there.
You need to organize your code so that Vehicle class definition appears, and then functions.h includes that.
So vehicle.h should look like:
#pragma once
#include <string>
// do NOT include functions.h
class Vehicle
{
// ...
};
and then functions.h should look like:
#pragma once
#include "vehicle.h"
// do NOT do "using namespace std;" in a header and don't include any unnecessary headers
void display(vector<Vehicle> &in);
and then functions.cpp should #include "functions.h" and contain the function body for display.
undeclared identifier means the compiler sees a name but don't see a declaration of that name (as a variable, class, function, etc.). It happens in your code in a few places, for example:
MyClass is used but not declared (main.cpp)
Vehicle is used but not declared (functions.h)
You use Vehicle.v but v not declared in class Vehicle (in addition, I doubt that this is what you intended - if you use class name Vehicle.v it means accessing a static variable, as opposed to vehicle.v).
It seems you lack some basic background. The most important thing is that you learn to decipher compiler errors, so at least you understand what went wrong.
I have the following code in a project:
#ifndef MAP_H
#define MAP_H
#include <string>
#include "MapCell.h"
using namespace std;
class Map{
public:
Map();
Map(int, int);
Map(string);
virtual ~Map();
private:
int grid_size;
MapCell * grid;
};
#endif
When I go to compile, I get the error "error: 'MapCell' does not name a type" yet when I comment out MapCell * grid and run this next block of code from main:
#include <iostream>
#include <cstdlib>
#include "MapCell.h"
using namespace std;
int main() {
MapCell * test_var;
test_var = new MapCell();
delete test_var;
cout << "Press enter to end process...";
cin.get();
cin.get();
return 0;
}
everything works just fine. I know my MapCell.h and .cpp files are in the right places and I'm guessing the compiler can see them since it works from main. I read around some other questions and most answers seem to point to either syntax errors or forward declarations which don't really fit here (unless I'm overlooking something)
Any ideas on what's going on here?
chris and greatwolf led me to the solution that fixed the problem. I needed to forward declare my MapCell class for the compiler to be able to link to the whole class.
I've been trying to include a structure called "student" in a student.h file, but I'm not quite sure how to do it.
My student.h file code consists of entirely:
#include<string>
using namespace std;
struct Student;
while the student.cpp file consists of entirely:
#include<string>
using namespace std;
struct Student {
string lastName, firstName;
//long list of other strings... just strings though
};
Unfortunately, files that use #include "student.h" come up with numerous errors like
error C2027: use of undefined type 'Student'
error C2079: 'newStudent' uses undefined struct 'Student' (where newStudent is a function with a `Student` parameter)
error C2228: left of '.lastName' must have class/struct/union
It appears the compiler (VC++) does not recognize struct Student from "student.h"?
How can I declare struct Student in "student.h" so that I can just #include "student.h" and start using the struct?
Try this new source :
student.h
#include <iostream>
struct Student {
std::string lastName;
std::string firstName;
};
student.cpp
#include "student.h"
struct Student student;
You should not place an using directive in an header file, it creates unnecessary headaches.
Also you need an include guard in your header.
EDIT: of course, after having fixed the include guard issue, you also need a complete declaration of student in the header file. As pointed out by others the forward declaration is not sufficient in your case.
C++, how to declare a struct in a header file:
Put this in a file called main.cpp:
#include <cstdlib>
#include <iostream>
#include "student.h"
using namespace std; //Watchout for clashes between std and other libraries
int main(int argc, char** argv) {
struct Student s1;
s1.firstName = "fred"; s1.lastName = "flintstone";
cout << s1.firstName << " " << s1.lastName << endl;
return 0;
}
put this in a file named student.h
#ifndef STUDENT_H
#define STUDENT_H
#include<string>
struct Student {
std::string lastName, firstName;
};
#endif
Compile it and run it, it should produce this output:
s1.firstName = "fred";
Protip:
You should not place a using namespace std; directive in the C++ header file because you may cause silent name clashes between different libraries. To remedy this, use the fully qualified name: std::string foobarstring; instead of including the std namespace with string foobarstring;.
Your student.h file only forward declares a struct named "Student", it does not define one. This is sufficient if you only refer to it through reference or pointer. However, as soon as you try to use it (including creating one) you will need the full definition of the structure.
In short, move your struct Student { ... }; into the .h file and use the .cpp file for implementation of member functions (which it has none so you don't need a .cpp file).
You've only got a forward declaration for student in the header file; you need to place the struct declaration in the header file, not the .cpp. The method definitions will be in the .cpp (assuming you have any).
Okay so three big things I noticed
You need to include the header file in your class file
Never, EVER place a using directive inside of a header or class, rather do something like std::cout << "say stuff";
Structs are completely defined within a header, structs are essentially classes that default to public
Hope this helps!
You can't.
In order to "use" the struct, i.e. to be able to declare objects of that type and to access its internals you need the full definition of the struct. So, it you want to do any of that (and you do, judging by your error messages), you have to place the full definition of the struct type into the header file.