Global Variables Across Multiple Classes Without Getting Redefinition errors? - c++

Extreme c++ beginner here. I have a global variable i've tried placing into a separate header file, and also into the specific classes themselves. Throughout, i'm receiving a "redefinition" error.
Here are the global variables:
enum GRADE {F, D, CMINUS, C, CPLUS, BMINUS, B, BPLUS, AMINUS, A};
const int BAR = 60;
const int MAXSTUDENT = 100;
I have them being used and called upon in two separate classes, called student.cpp and course.cpp. They are contained in "global.cpp"
here is the header in student.cpp
#include "student.hpp"
#include "global.cpp"
#include <iostream>
using namespace std;
Here is the header in course.cpp
#include "course.hpp"
#include "student.cpp"
#include <iostream>
using namespace std;
No matter what combination of headers, or attempts to split the global variables into the classes they are being used by, i am getting a "redefinition" error. If i uninclude "#student.cpp" in the course.cpp section, i won't get the error, but i need the student.cpp for the course.cpp to work.
I'm way out of my element, would appreciate any help.

Create a file global.h. In that file you can declare your global variables. enum GRADE is not a variable but a type. It is important to remember that you can declare types and variables multiple times, but you can define them only once. So do not define them in the header, just declare them. If you want to use the same global variable across multiple cpp files you must declare them with external linkage.
/* File global.h */
#pragma once
extern const int BAR;
extern const int MAXSTUDENT;
This is an example student.h:
/* File student.h */
#pragma once
enum GRADE {F, D, CMINUS, C, CPLUS, BMINUS, B, BPLUS, AMINUS, A};
class Student
{
public:
Student();
virtual ~Student();
/* put more members here */
};
Here is an example course.h:
/* File course.h */
#pragma once
#include "student.h"
class Course
{
public:
Course();
virtual ~Course();
void addStudent(Student& student);
private:
std:vector<Student*> students;
}
Then you can choose one *.cpp file to define the globals.
For example you put them in student.cpp. Then you can already use them in student.cpp:
/* File student.cpp */
#include "student.h"
const int BAR = 60;
const int MAXSTUDENT = 100;
/* definition of student methods ... for example */
Student::Student()
{ }
Student::~Student()
{ }
In that case you do not include the global.h in the student.cpp file.
Also please do not #include any *.cpp files.
Put the declaration of your student class into student.h, put the definition of methods of the student class into student.cpp.
In the course.cpp just include global.h, course.h. But the student.h is already included via course.h. Then you can also use the global variable in this cpp.
/* file course.cpp */
#include "course.h"
#include "global.h"
/* definition of course methods ... for example */
Course::Course()
{ }
Course::~Course()
{ }
Course::addStudent(Student& student)
{
if(students.size() < MAXSTUDENT) {
// ......
}
}
Hope that helps you.

Related

Initialize with global variables in c++

I've tried to read the thread below about creating global variables that can be used between multiple files but it will not work.
Global Variable within Multiple Files
variable.h
extern const int variable1;
file1.h
class fileOne{
private:
fileTwo ft[variable1];
public:
//some functions...
};
file2.h
class fileTwo{
private:
//some variables
public:
//some functions
};
main.cpp
int main(){
int variable1 = 2;
fileOne fo;
}
When I run this, the compiler says the following:
error: array bound is not an integer constant before ']' token
Is it possible to declare a global variable and use it in the manner above?
Also: Is this an array? fileTwo ft[variable1]; Is fileTwo a class?
A fixed-sized array needs to have its size specified at compile-time, which means only a compile-time constant can be used. You can't use an externed variable for the size of the array, even if it is declared as const, as the compiler simply doesn't know the actual value of the variable since it is in another translation unit.
Also, in main.cpp, you can't declare the extern'ed variable as a local variable, it needs to be in global scope instead.
For what you are trying to do, there is no reason to use extern at all. Just declare variable1 with a constant value directly in variable.h, and then #include that file where needed, eg:
variable.h:
#ifndef VARIABLE_H
#define VARIABLE_H
static const int variable1 = 2;
#endif
file1.h:
#ifndef FILE1_H
#define FILE1_H
#include "file2.h"
#include "variable.h"
class fileOne{
private:
fileTwo ft[variable1];
public:
//some functions...
};
#endif
file2.h:
#ifndef FILE2_H
#define FILE2_H
class fileTwo{
private:
//some variables
public:
//some functions
};
#endif
main.cpp:
#include "file1.h"
int main(){
fileOne fo;
}
To define an array you need to specify the actual size of the array and the size must be something the compiler can turn into a constant. Since variable1 can't be turned into a constant, the compiler issues the error.
What you can do is something like the following.
file1.h
class fileOne{
private:
fileTwo ft[variable1];
public:
//some functions...
};
file2.h
class fileTwo{
private:
//some variables
public:
//some functions
};
main.cpp
static const int variable1 = 2; // const int for the size of the ft array of class fileOne
#include "file2.h" // class fileTwo definition is needed for class fileOne
#include "file1.h" // class fileOne has a dependency on class fileTwo
int main(){
fileOne fo; // define a fileOne object named fo
// do more stuff
}
Is it possible to declare a global variable and use it in the manner above?
Yes, but like Remy pointed out, you would need to move this variable to a header file that will be #included from file1.h
Also: Is this an array? fileTwo ft[variable1];
Yes, this is called a C-array. The C++ standard library also has C++ arrays (i.e. fixed size) using std::array<type, size>, which are much more convenient and safe to use, as well as containers like vector, list, etc.
If you want to use a C++ array, you can declare it this way for you case:
#include <array>
std::array ft<fileTwo, variable1>;

Can't find find out why it doesn't compile [duplicate]

I have a very simple program that doesn't compile due to multiple definition error. It is here:
main.cpp
#include <iostream>
#include "read_p.h"
using namespace std;
int main()
{
return 0;
}
read_p.cpp
#include "read_p.h"
using namespace std;
void read_p()
{
/*
some code here
*/
}
read_p.h
#ifndef READ_P_H
#define READ_P_H
#include "buildings.h"
void read_p();
#endif
buildings.h
#ifndef BUILDINGS_H
#define BUILDINGS_H
#include "flag.h"
using namespace std;
/*
some class here
*/
#endif
flag.h
#ifndef FLAG_H
#define FLAG_H
using namespace std;
class
Test
{
private:
public:
int test_var;
Test(int);
};
Test::Test(int a)
{
test_var = a;
}
#endif
The compiler gives me the error that the constructor Test::Test is defined multiple times. Unlike questions I find online, this error is not due to including the cpp-file instead of the h-file.
Question: Where does the multiple definition of the constructor occur? And is the proper way to circumvent the issue by making the constructur inline?
Change
Test(int);
to
inline Test(int);
Even better, fix your class definition to define member functions inline, which makes them implicitly inline:
class Test
{
public:
int test_var;
Test(int a) : test_var(a) {}
};
Otherwise, as always, defining a function in a header means that it gets defined in every translation unit that includes that header, which leads to multiple definitions.

Multiple definition of constructor

I have a very simple program that doesn't compile due to multiple definition error. It is here:
main.cpp
#include <iostream>
#include "read_p.h"
using namespace std;
int main()
{
return 0;
}
read_p.cpp
#include "read_p.h"
using namespace std;
void read_p()
{
/*
some code here
*/
}
read_p.h
#ifndef READ_P_H
#define READ_P_H
#include "buildings.h"
void read_p();
#endif
buildings.h
#ifndef BUILDINGS_H
#define BUILDINGS_H
#include "flag.h"
using namespace std;
/*
some class here
*/
#endif
flag.h
#ifndef FLAG_H
#define FLAG_H
using namespace std;
class
Test
{
private:
public:
int test_var;
Test(int);
};
Test::Test(int a)
{
test_var = a;
}
#endif
The compiler gives me the error that the constructor Test::Test is defined multiple times. Unlike questions I find online, this error is not due to including the cpp-file instead of the h-file.
Question: Where does the multiple definition of the constructor occur? And is the proper way to circumvent the issue by making the constructur inline?
Change
Test(int);
to
inline Test(int);
Even better, fix your class definition to define member functions inline, which makes them implicitly inline:
class Test
{
public:
int test_var;
Test(int a) : test_var(a) {}
};
Otherwise, as always, defining a function in a header means that it gets defined in every translation unit that includes that header, which leads to multiple definitions.

C++: Multiple definition error when including parent class?

I am writing a simple banking program with derived classes and I am running into a Multiple definition of <method name> error when including parent class.
Keep in mind that I just started coding in C++ yesterday, and moving over from Java/PHP, handling headers/definitions is a bit confusing for me. Please correct anything you see wrong!
Here is a sample of my files/code:
Files
Account.h
Account.cpp (Super)
ChequingAccount.cpp (Child)
SavingsAccount.cpp (Child)
The error is reproduce-able when including the parent class (Account.cpp) into any file. I have reduced my code by a lot, but it should give you an idea of how I am handling inheritance.
To clarify, when I #include the child classes to any file (ChequingAccount.cpp) works fine, and inherited functions work as expected. However, when I #include the parent class (Account.cpp) breaks the compiler with the Multiple definition of <method name> error for all methods.
Again, I am not sure if this is the proper way to do it, but this is what I understand from tutorials I have found.
Code
Account.h
#ifndef ACCOUNT_H
#define ACCOUNT_H
class Account
{
protected:
double m_balance;
public:
Account(double balance); // Constructor.
virtual ~Account(); // Destructor.
// Accessor Methods.
double getBalance() const;
// Mutator Methods.
virtual void withdrawFunds(double amount);
void depositFunds(double amount);
};
#endif
Account.cpp (Superclass)
#include "Account.h"
Account::Account(double balance = 0)
{
m_balance = balance;
}
Account::~Account()
{
// TODO: Delete this data structure...
}
double Account::getBalance() const
{
return m_balance;
}
void Account::withdrawFunds(double amount)
{
m_balance -= amount;
}
void Account::depositFunds(double amount)
{
m_balance += amount;
}
ChequingAccount.cpp (Child)
#include "Account.h"
class ChequingAccount: public Account
{
public:
ChequingAccount(int id, int userId, double balance) : Account(id, balance){};
void withdrawFunds(double amount)
{
// Override parent method.
}
};
Any help would be greatly appreciated! Thank you!
When you #include "some file.cpp", you are directing the compiler to copy the contents of that cpp file to that point in the program. This will create two compiled versions of your "some file" which will lead to "Multiple Definitions."
First of all, "identical" functions declared in base class and sub-class will not cause multiple definition error.
Here is just one example and explanation aiming to help you understand my point:
main.cpp
class father{
void fun();
}
void father::fun(){}
class son : public father{
void fun();
}
void son::fun(){}
int main()
{
return 0;
}
You compile it, and definitely no multiple definition error. In Java, we define functions within classes. In C++, only inline functions are defined within classes and others are declarations, which can be declared whatever times you like. See the definition syntax : father::fun son::fun. These actually define two different functions, one is in father and the other is in son. So there are no multiple definition error. Once more, in class declarations you can only define inline functions and can only declare non-inline functions. So there are on multiple definition errors at all. This just aims to help you understand it in a grammar way.
BTW, if compiler failed to inline, there would be no multiple definition error too because even though you define inline functions in header files and include the files anywhere, inline functions are of internal linkage.
I compiled your codes and got different errors regarding your defined constructors. Anyway, including cpp files using "include" means you don't get the point of implementation file and interface file.
You need to declare the child's method as a member of the child class explicitly in the child's .cpp file as well. See below:
ChequingAccount.cpp (Child)
#include "Account.h"
class ChequingAccount: public Account
{
public:
ChequingAccount(int id, int userId, double balance) : Account(id, balance){};
void ChequingAccount::withdrawFunds(double amount)
{
// Override parent method.
}
};
You already have void Account::withdrawFunds(double) defined when you define void ChequingAccount::withdrawFunds(double).
Try virtual void ChequingAccount::withdrawFunds(double)
The virtual keyword is similar to overriding in Java.
In short, you should not include a cpp file.
The reason you get a multiple definition error actually has nothing to do with class inheritance.
Consider a simple example:
add.h:
#ifndef __ADD_H_
#define __ADD_H_
int add(int a);
#endif
add.cpp:
#include "add.h"
int add(int a) { return a + 1; }
main.cpp:
#include "add.h"
int main() { return add(-1); }
The way C++ dealing with #include directive is simply to copy-paste the included file and replace the #include line. So if we expand the above files manually, we will get something like:
add.cpp:
#ifndef __ADD_H_
#define __ADD_H_
int add(int a);
#endif
int add(int a) { return a + 1; }
main.cpp:
#ifndef __ADD_H_
#define __ADD_H_
int add(int a);
#endif
int main() { return add(-1); }
which will work just fine. (We are allowed to have multiple declarations of a function)
However, if you decide to include the .cpp file instead of the .h file like the code below:
main.cpp:
#include "add.cpp" // notice here
int main() { return add(-1); }
And if you expand it as we just did:
add.cpp:
#ifndef __ADD_H_
#define __ADD_H_
int add(int a);
#endif
int add(int a) { return a + 1; }
main.cpp:
#ifndef __ADD_H_
#define __ADD_H_
int add(int a);
#endif
int add(int a) { return a + 1; }
int main() { return add(-1); }
You will see the code includes multiple definitions of the function add, one of which is in add.cpp and the other one is in main.cpp. When linking these two files together (each .cpp file is compiled separately using a compiler and then linked together using a linker), the linker will be confused by two definitions of add and doesn't know which one to use, so it will start to complain.

Is this possible in C++? toString(ClassName* class)

I'd like to use toString with class argument, but for some reason there is an error.
The code is:
Animal.h
#include "Treatment.h"
#include "jdate.h"
#include <vector>
class Animal{
protected:
int id;
double weight;
int yy;
int mm;
int dd;
double accDose;
char sex;
vector<Treatment*> treatArray;
public:
Animal();
Animal(int newid, double newweight, int yy, int mm, int dd, char newsex, vector<Treatment*> treatArray);
~Animal();
};
Treatment.h
#ifndef TRE_H
#define TRE_H
#include <string>
#include <sstream>
#include "jdate.h"
#include "Animal.h"
#include "Cattle.h"
#include "Sheep.h"
class Treatment{
private:
int id;
jdate dayTreated;
double dose;
public:
Treatment(int id,jdate dayTreated, double dose);
Treatment();
~Treatment();
string toString(Animal* a);
};
#endif
Treatment.cpp
#include "Treatment.h"
using namespace std;
Treatment::Treatment(int newid,jdate newdayTreated, double newdose){
id=newid;
dayTreated = newdayTreated;
dose = newdose;
}
Treatment::Treatment(){
id=0;
dose=0;
}
Treatment::~Treatment(){}
string Treatment::toString(Animal* a)
{
string aa;
return aa;
}
toString is in Treatment class. I'm not sure but I think it's because Animal has
vector treatArray;. Does it actually matter?
Sorry that I cannot put the error messages here, because once I declare toString, for some reason tons of errors occur, such as
Error 1 error C2065: 'Treatment' : undeclared identifier l:\2011-08\c++\assignment\drug management\drug management\animal.h 30 1 Drug Management
// Animal.h
// #include "Treatment.h" remove this
class Treatmemt; // forward declaration
class Animal
{
...
};
In your version, Treatment.h and Animal.h include each other. You need to resolve this circular dependency using forward declaration. In .cpp files, include all necessary h-files.
You include Animal.h in Treatment.h before the class Treatment is defined, that's why you're getting the error.
Use forward declaration to solve this:
In Animal.h add line
class Treatment;
You've not used std namespace in both header files.
So, use std::string instead of string. Because string is defined in std namespace.
Simillarly use std::vector instead of vector.
There are a few problems with your code. First of all, Animal.h should have an include guard as Treatment.h has:
#ifndef ANIMAL_H
#define ANIMAL_H
// Your code here
#endif
I'd also suggest that you give a longer name to Treatment.h's guard, you'll reduce the risk of using the same name elsewhere.
Using guards will ensure that you don't have a circular inclusion. Still you do have a circular dependency because the Treatment class needs to know about the Animal class and vice versa. However, as in both cases you used pointers to the other class, the full definitions are not required and you can - should, actually - replace in both header files the inclusion of the other with a simple declaration. For instance in Animal.h remove
#include "Treatment.h"
and add
class Treatment;
Both Treatment.cpp and Animal.cpp must include both Treatment.h and Animal.h.