Several strange errors when building project using separate files C++ - c++

I'm able to build and run a particular project in Visual Studio when all of the code is in one main .cpp file, but when I separate the file into a class (.cpp and .h) and main .cpp file, I get several weird errors.
Here is the code when it's in 3 separate files, and not working:
//main.cpp
#include "student.h"
#include <string>
#include <iostream>
using namespace std;
int main()
{
std::cout << "Hello World!\n";
Student student;
student.setStudentID("A1C");
student.print();
}
//Student.h
#ifndef STUDENT_H
#define STUDENT_H
class Student
{
public:
Student();
string getStudentID() const;
void setStudentID(string studentID);
void print();
private:
string studentID;
};
#endif
//Student.cpp
#include "Student.h"
#include <string>
#include <iostream>
using namespace std;
Student::Student() {
this->studentID = "default";
}
string Student::getStudentID() const {
return this->studentID;
}
void Student::setStudentID(string studentID) {
this->studentID = studentID;
}
void Student::print() {
cout << "student ID: " << studentID << endl;
}
Here is the code when it's all in one main.cpp file, and working:
#include <string>
#include <iostream>
using namespace std;
class Student
{
public:
Student();
string getStudentID(); //const?
void setStudentID(string studentID);
void print();
private:
string studentID;
};
int main()
{
std::cout << "Hello World!\n";
Student student;
student.setStudentID("A1C");
student.print();
}
Student::Student() {
this->studentID = "default";
}
string Student::getStudentID() { //const?
return this->studentID;
}
void Student::setStudentID(string studentID) {
this->studentID = studentID;
}
void Student::print() {
cout << "student ID: " << studentID << endl;
}
Here are some of the errors that I get:

In the file Student.h you are using string, but string is not (yet) known. Read the Include file from top to bottom. Nowhere in the file is there any hint as to what string is supposed to be.
#include <string> in your Student.h file will introduce std::string to the file. From here on, std::string will be valid. But that's still not enough, since you are using string and not std::string in your class.
Do not include a using namespace std in your header file. If you do so, you force this namespace on all your "customers" of the header file. If any other file includes your Student.h with the using namespace in it, they will also get the using namespace... statement, even if they do not want it. Headerfiles should be self contained and should not introduce stuff, others may not want.
Also do not add a using std::string in your header file. While not as bad as a using namespace std there may be (and later in your professional life will be) instances, where you have different kinds of string. Perhaps a std::string and an oldfashioned::string or utf_something::string.
For simplicity, just write std::string studentId. IOW, use the fully qualified name of string in your header file.
In .cpp files these rules are somewhat relaxed, since no other file will include your .cpp file.
Bonus:
lookup #pragma once
always include system headers before your own headers
But beware of include order. Every header file should include all headers it needs, because ...
... the worst thing that can happen is that your code changes depending on the order in which you include headers. It should not matter. Including "Student.h" should introduce the Student class and nothing else.
Bonus++
take your time to learn about the C(++) preprocessor. #include is not really a C++ language statement like class, for etc... It is just a directive for the compiler to read the included file first.
Your compiler will have a switch (such as /P with Microsoft Visual C++) which will not compile the code but produce the actual included files and store the in a *.p (or something) file. It will let you see what the preprocessor does with your code before it is passed on to the compiler. It's an interesting and teaching experience. Try it. Don't be put off by the seemingly complex file. Search for "class Student" in that file and take it from there.

change student.h to this
//Student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <string>
class Student
{
public:
Student();
std::string getStudentID() const;
void setStudentID(std::string studentID);
void print();
private:
std::string studentID;
};
#endif
and it compiles and runs fine
BTW.
dont do this
void Student::setStudentID(string studentID) {
this->studentID = studentID;
}
have a naming convention for fields in a class so they are distinct
ie
//Student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <string>
class Student
{
public:
Student();
std::string getStudentID() const;
void setStudentID(std::string studentID);
void print();
private:
std::string studentID_; <<<<========
};
then
void Student::setStudentID(string studentID) {
studentID_ = studentID;
}
why, because
First its the accepted way in c++ world (the naming standard might differ, m_ prefix is common too)
second you might write this
void Student::setStudentID(string studentID) {
studentID = studentID;
}
which will compile but is maybe not what you mean. Of course here its obvious but in denser code, not so much

Related

Visual Studio 2019 debugger steps into header file instead of cpp

I have created a small c++ application with a header file, a cpp file, and a main function.
I expected that the header file would be an interface, that would just define my functions and properties, but the cpp file would be the one to implement.
However when I create my files, in my main function I have a breakpoint and try to step into my method, it just takes me straight to the header file definition instead of the implementing cpp file. Here is my code:
//header file
#pragma once
#include <string>
#include <SQLAPI.h>
class DbConnection
{
public:
int Id, Age;
std::string Name;
void ConnectToDatabase(const std::string databaseName) { }
void Retrieve(const std::string table) { }
};
Here is my cpp file:
#include "DbConnection.h"
#include <string>
#include <SQLAPI.h>
#include <iostream>
SAConnection sqlCon;
SACommand sqlCmd(&sqlCon);
int Id, Age;
std::string Name;
void ConnectToDatabase(const std::string databaseName)
{
sqlCon.Connect(
databaseName,
",
",
SA_SQLServer_Client);
}
void Retrieve(const std::string table)
{
//code to retrieve data
std::cout << "success";
}
My main function which is in a separate cpp file. I set a breakpoint and attempt to step into the method Retrieve and it takes me to the header file instead of the cpp. Any help with debugging is appreciated.
#include "DbConnection.h"
#include <stdio.h>
#include <iostream>
int main()
{
DbConnection con;
con.ConnectToDatabase(
"databaseParameter");
con.Retrieve("tableParameter");
return 0;
}
I assume it is one of two things, either my debugger in visual studio 2019 is not set to the proper setting, or it has to do with how my #include "DbConnection.h" statements are included in both cpp files.
Two things:
You have to write in the cpp file
void DbConnection::ConnectToDatabase(const std::string databaseName)
{
...
}
and so for the Retrieve function to tell the compiler that this is the function of the class.
You actually implemented the function in the header file when you put {} after the function declaration.

Why can't my .cpp file resolve variables declared in my .h file?

I just started learning how to write C++ code using CLion but I am running into some issues using classes. To my understanding, functions and methods are declared in the .h file and then they can be used in the .cpp file. If I do it this way then I get the error message "Can't resolve variable studentName". The message goes away if I declare the variable in the .cpp file but then doesn't that defeat the purpose of the .h file? Thank you in advance to whoever can help me resolve this issue.
Student.h
#ifndef PRACTICE_STUDENT_H
#define PRACTICE_STUDENT_H
#include <string>
class Student {
std:: string studentName;
int gradeLevel;
Student :: Student(std:: string studentName, int gradeLevel);
std:: string getName();
};
#endif //PRACTICE_STUDENT_H
Student.cpp
#include "Student.h"
#include <string>
Student:: Student(std:: string i_studentName, int i_gradeLevel){
gradeLevel = i_gradeLevel;
}
std:: string getName() {
return studentName;
}
main.cpp
#include <iostream>
#include "Student.h"
using namespace std;
int main(){
Student Carlton = Carlton.("Carlton", 16);
cout << Carlton.getName();
return 0;
}
getName is a member function of the Student class. To implement it in your .cpp file, you need to properly indicate that it belongs to that class:
std::string Student::getName() {
return studentName;
}

Getting class type redefinition and a few other errors

I'm creating a student data management console application for a project. I created a class called Student which is storing all the data that a student needs to have, and it also has all the getters and setters associated with it. Here is how all my files are laid out:
Student.h
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
string name;
string id;
string email;
int presentation;
int essay1;
int essay2;
int project;
public:
//constructor
//Student();
//setters
void set_name(string);
void set_id(string);
void set_email(string);
void set_presentation(int);
void set_essay1(int);
void set_essay2(int);
void set_project(int);
//getters
string get_name();
string get_id();
string get_email();
int get_presentation();
int get_essay1();
int get_essay2();
int get_project();
};
Student.cpp
#include <iostream>
#include <string>
#include "Student.h"
using namespace std;
//constructor definition
/*
Student::Student(void) {
cout << "Student created" << endl;
}
*/
//setter definition
void Student::set_name(string s) {
name = s;
}
void Student::set_id(string s) {
id = s;
}
void Student::set_email(string s) {
email = s;
}
void Student::set_presentation(int a) {
presentation = a;
}
void Student::set_essay1(int a) {
essay1 = a;
}
void Student::set_essay2(int a) {
essay2 = a;
}
void Student::set_project(int a) {
project = a;
}
//getter definition
string Student::get_name() {
return name;
}
string Student::get_id() {
return id;
}
string Student::get_email() {
return email;
}
int Student::get_presentation() {
return presentation;
}
int Student::get_essay1() {
return essay1;
}
int Student::get_essay2() {
return essay2;
}
int Student::get_project() {
return project;
}
Main.cpp
#include <iostream>
#include <string>
#include "Student.h"
using namespace std;
int main() {
cout << "Hello World!" << endl;
Student student1;
Student student2;
Student student3;
student1.set_name("John");
student2.set_name("Bob");
student3.set_name("Carl");
return 0;
}
When I try to run my program, I get, amongst others, the following errors:
Error 1 error C2011: 'Student' : 'class' type redefinition
Error 2 error C2079: 'student1' uses undefined class 'Student'
Error 5 error C2228: left of '.set_name' must have class/struct/union
Error 9 error C2027: use of undefined type 'Student'
How can I go about fixing this issue?
I'm quite sure this is an error caused by the fact that student.h is included twice in a certain .cpp file. Thus you need to use so-called header guards to make sure the file is only included once in every .cpp file:
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <string>
using namespace std;
class Student {
/* ... */
};
#endif
The idea behind this is that an #include is a preprocessor directive that results in the argument file being copied into the file where the #include was issued. Hence, if files A and B include Student.h, and file C includes both files A and B, then the declaration of class Student is going to end up duplicated. Hence the error. The above macros make sure that this doesn't happen.
Edit as per the question author's comment:
#pragma once is the same as #ifndef .. #define #endif but non-standard .
See #pragma once vs include guards? for reference.
I had the same error. I just clean and rebuild the solution and error resolved.

Linking c++ files using CMakeLists.txt

Okay, so I just started dabbing into c++ and I'm hoping to get ahead on my classes in the fall but instead of using the a compiler I've been using nitrous.io as an IDE. Anyways long story short, I'm using CMakeLists.txt to compile and run but I've been running into a lot of difficulties when trying to link together an interface, it's corresponding cpp file and a main function.
Gradebook.h
//Gradebook.h
#include <string>
using namespace std;
class Gradebook
{
public:
Gradebook(string n);
Gradebook();
void setCourse(string n);
string getCourse();
void displayMessage();
private:
string course;
};
Gradebook.cpp
//Gradebook.cpp
#include "Gradebook.h"
#include <iostream>
using namespace std;
Gradebook::Gradebook(string n)
{
course = n;
}
Gradebook::Gradebook()
{
cout << "Default constructor used." << endl;
}
void Gradebook::setCourse(string n)
{
course = n;
}
string Gradebook::getCourse()
{
return course;
}
void Gradebook::displayMessage()
{
cout << "Welcome to " << course << "'s gradebook." << endl;
}
GradebookRunner.cpp - main function
#include "Gradebook.h"
int main()
{
Gradebook g("Intro to c++");
g.displayMessage();
return 0;
}
CMakeLists.txt - I'm 95% sure that the syntax and linking is done correctly in the .h and .cpp files, this is where I believe I'm making the mistake.
##I've tried to use different combinations of Gradebook and Gradebook.cpp in here.
cmake_minimum_required(VERSION 2.6)
project(Gradebook)
add_executable(Gradebook Gradebook.cpp)
Any help will be much appreciated :D
Simply add all files that belong to the executable (both headers and source files, so you have them all in IDE and dependencies are correctly resolved by CMake).
add_executable(Gradebook Gradebook.cpp GradebookRunner.cpp Gradebook.h)
Note that GLOB feature could be tricky.

Redefinition of class

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.