Home > Software engineering >  Several strange errors when building project using separate files C
Several strange errors when building project using separate files C

Time:02-18

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:

CodePudding user response:

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.

CodePudding user response:

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

  •  Tags:  
  • c
  • Related