Multiple linker errors

Hi everyone,

I have started to study C++ language as part of my university studies and liked it very much.
Now I'm trying improve my skills with a course from EdX, but there is something I can't seem to understand after a few days of searching.

I'm trying to separate header and implementation files as recommended.
The program structure is :
- main.cpp
- Student.h - class file for Student
- Student.cpp - Implementation file with Student methods.

Here is my code :

Student.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#ifndef Student_h
#define Student_h


class Student
{
private:
    std::string firstName;
    std::string lastName;
    int age;
    std::string address;
    std::string city;
    std::string phone;


public:
    Student() = default;
    Student(std::string fn, std::string ln, int a) : firstName(fn), lastName(ln), age(a) {}


    //Prototypes

    std::string getFirstName();
    std::string getLastName();
    int getAge();
    std::string getAddress();
    std::string getCity();
    std::string getPhone();

    void printInfo();

    //Set
    void setFirstName(std::string fn);
    void setLastName(std::string ln);
    void setAge(int a);
    void setAddress(std::string add);
    void setCity(std::string c);
    void setPhone(std::string p);


};

#endif // !Student_h



Student.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "Student.h"
#include <string>


    //Get
    Student::getFirstName() { return this->firstName; }
    Student::getLastName() { return this->lastName; }
    Student::getAge() { return this->age; }
    Student::getAddress() { return this->address; }
    Student::getCity() { return this->city; }
    Student::getPhone() { return this->phone; }

    Student::printInfo()
    {
        std::std::cout << "Student details: " << '\n';
        std::cout << "Name: " << firstName << " " << lastName << '\n';
        std::cout << "Address: " << city << " " << address << '\n';
        std::cout << "Age: " << age << '\n';
        std::cout << "Phone: " << phone <<  '\n';
    }

    //Set
    Student::setFirstName(fn) { this->firstName = fn; }
    Student::setLastName(ln) { this->firstName = ln; }
    Student::setAge(int a) { this->age = a; }
    Student::setAddress(add) { this->address = add; }
    Student::setCity(c) { this->city = c; }
    Student::setPhone(p) { this->phone = p; }    
    



And main.cpp file
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include "Student.h"
#include <string>


int main()
{
    Student s;
    s.setAge(29);

}


But when I try compile I get below errors
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
➜  ModuleTwo git:(master) ✗ g++ Student.cpp Main.cpp
In file included from Student.cpp:1:0:
Student.h:8:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string firstName;
          ^~~~~~
Student.h:9:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string lastName;
          ^~~~~~
Student.h:11:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string address;
          ^~~~~~
Student.h:12:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string city;
          ^~~~~~
Student.h:13:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string phone;
          ^~~~~~
Student.h:18:25: error: expected ‘)’ before ‘fn’
     Student(std::string fn, std::string ln, int a) : firstName(fn), lastName(ln), age(a) {}
                         ^~
Student.h:23:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string getFirstName();
          ^~~~~~
Student.h:24:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string getLastName();
          ^~~~~~
Student.h:26:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string getAddress();
          ^~~~~~
Student.h:27:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string getCity();
          ^~~~~~
Student.h:28:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string getPhone();
          ^~~~~~
Student.h:33:28: error: ‘std::string’ has not been declared
     void setFirstName(std::string fn);
                            ^~~~~~
Student.h:34:27: error: ‘std::string’ has not been declared
     void setLastName(std::string ln);
                           ^~~~~~
Student.h:36:26: error: ‘std::string’ has not been declared
     void setAddress(std::string add);
                          ^~~~~~
Student.h:37:23: error: ‘std::string’ has not been declared
     void setCity(std::string c);
                       ^~~~~~
Student.h:38:24: error: ‘std::string’ has not been declared
     void setPhone(std::string p);
                        ^~~~~~
Student.cpp:6:27: error: ISO C++ forbids declaration of ‘getFirstName’ with no type [-fpermissive]
     Student::getFirstName() { return this->firstName; }
                           ^
Student.cpp:6:27: error: no ‘int Student::getFirstName()’ member function declared in class ‘Student’
Student.cpp:7:26: error: ISO C++ forbids declaration of ‘getLastName’ with no type [-fpermissive]
     Student::getLastName() { return this->lastName; }
                          ^
Student.cpp:7:26: error: no ‘int Student::getLastName()’ member function declared in class ‘Student’
Student.cpp:8:21: error: ISO C++ forbids declaration of ‘getAge’ with no type [-fpermissive]
     Student::getAge() { return this->age; }
                     ^
Student.cpp:9:25: error: ISO C++ forbids declaration of ‘getAddress’ with no type [-fpermissive]
     Student::getAddress() { return this->address; }
                         ^
Student.cpp:9:25: error: no ‘int Student::getAddress()’ member function declared in class ‘Student’
Student.cpp:10:22: error: ISO C++ forbids declaration of ‘getCity’ with no type [-fpermissive]
     Student::getCity() { return this->city; }
                      ^
Student.cpp:10:22: error: no ‘int Student::getCity()’ member function declared in class ‘Student’
Student.cpp:11:23: error: ISO C++ forbids declaration of ‘getPhone’ with no type [-fpermissive]
     Student::getPhone() { return this->phone; }
                       ^
Student.cpp:11:23: error: no ‘int Student::getPhone()’ member function declared in class ‘Student’
Student.cpp:13:24: error: ISO C++ forbids declaration of ‘printInfo’ with no type [-fpermissive]
     Student::printInfo()
                        ^
Student.cpp:13:5: error: prototype forint Student::printInfo()’ does not match any in class ‘Student’
     Student::printInfo()
     ^~~~~~~
In file included from Student.cpp:1:0:
Student.h:30:10: error: candidate is: void Student::printInfo()
     void printInfo();
          ^~~~~~~~~
Student.cpp:23:26: error: expected constructor, destructor, or type conversion before ‘(’ token
     Student::setFirstName(fn) { this->firstName = fn; }
                          ^
Student.cpp:24:25: error: expected constructor, destructor, or type conversion before ‘(’ token
     Student::setLastName(ln) { this->firstName = ln; }
                         ^
Student.cpp:25:26: error: ISO C++ forbids declaration of ‘setAge’ with no type [-fpermissive]
     Student::setAge(int a) { this->age = a; }
                          ^
Student.cpp:25:5: error: prototype forint Student::setAge(int)’ does not match any in class ‘Student’
     Student::setAge(int a) { this->age = a; }
     ^~~~~~~
In file included from Student.cpp:1:0:
Student.h:35:10: error: candidate is: void Student::setAge(int)
     void setAge(int a);
          ^~~~~~
Student.cpp:26:24: error: expected constructor, destructor, or type conversion before ‘(’ token
     Student::setAddress(add) { this->address = add; }
                        ^
Student.cpp:27:21: error: expected constructor, destructor, or type conversion before ‘(’ token
     Student::setCity(c) { this->city = c; }
                     ^
Student.cpp:28:22: error: expected constructor, destructor, or type conversion before ‘(’ token
     Student::setPhone(p) { this->phone = p; }



Please, could you help me understand what I'm doing wrong here?

I've already tried to put function return types(void) in front of the declarations in Student.cpp but didn't work.


Many thanks,
Bavarian
Student.h uses std::string without including <string> first.
I added #include <string> in Student.h file but still getting errors when trying to compile Student.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
Student.cpp:6:27: error: ISO C++ forbids declaration of ‘getFirstName’ with no type [-fpermissive]
     Student::getFirstName() { return this->firstName; }
                           ^
Student.cpp:6:5: error: prototype forint Student::getFirstName()’ does not match any in class ‘Student’
     Student::getFirstName() { return this->firstName; }
     ^~~~~~~
In file included from Student.cpp:1:0:
Student.h:26:17: error: candidate is: std::__cxx11::string Student::getFirstName()
     std::string getFirstName();
                 ^~~~~~~~~~~~
Student.cpp:7:26: error: ISO C++ forbids declaration of ‘getLastName’ with no type [-fpermissive]
     Student::getLastName() { return this->lastName; }
                          ^
Student.cpp:7:5: error: prototype forint Student::getLastName()’ does not match any in class ‘Student’
     Student::getLastName() { return this->lastName; }
     ^~~~~~~
In file included from Student.cpp:1:0:
Student.h:27:17: error: candidate is: std::__cxx11::string Student::getLastName()
     std::string getLastName();
                 ^~~~~~~~~~~
Student.cpp:8:21: error: ISO C++ forbids declaration of ‘getAge’ with no type [-fpermissive]
     Student::getAge() { return this->age; }
                     ^
Student.cpp:9:25: error: ISO C++ forbids declaration of ‘getAddress’ with no type [-fpermissive]
     Student::getAddress() { return this->address; }
                         ^
Student.cpp:9:5: error: prototype forint Student::getAddress()’ does not match any in class ‘Student’
     Student::getAddress() { return this->address; }
     ^~~~~~~
In file included from Student.cpp:1:0:
Student.h:29:17: error: candidate is: std::__cxx11::string Student::getAddress()
     std::string getAddress();
                 ^~~~~~~~~~
Student.cpp:10:22: error: ISO C++ forbids declaration of ‘getCity’ with no type [-fpermissive]
     Student::getCity() { return this->city; }
                      ^
Student.cpp:10:5: error: prototype forint Student::getCity()’ does not match any in class ‘Student’
     Student::getCity() { return this->city; }
     ^~~~~~~
In file included from Student.cpp:1:0:
Student.h:30:17: error: candidate is: std::__cxx11::string Student::getCity()
     std::string getCity();
                 ^~~~~~~
Student.cpp:11:23: error: ISO C++ forbids declaration of ‘getPhone’ with no type [-fpermissive]
     Student::getPhone() { return this->phone; }
                       ^
Student.cpp:11:5: error: prototype forint Student::getPhone()’ does not match any in class ‘Student’
     Student::getPhone() { return this->phone; }
     ^~~~~~~
In file included from Student.cpp:1:0:
Student.h:31:17: error: candidate is: std::__cxx11::string Student::getPhone()
     std::string getPhone();
                 ^~~~~~~~
Student.cpp:13:24: error: ISO C++ forbids declaration of ‘printInfo’ with no type [-fpermissive]
     Student::printInfo()
                        ^
Student.cpp:13:5: error: prototype forint Student::printInfo()’ does not match any in class ‘Student’
     Student::printInfo()
     ^~~~~~~
In file included from Student.cpp:1:0:
Student.h:33:10: error: candidate is: void Student::printInfo()
     void printInfo();
          ^~~~~~~~~
Student.cpp:23:26: error: expected constructor, destructor, or type conversion before ‘(’ token
     Student::setFirstName(fn) { this->firstName = fn; }
                          ^
Student.cpp:24:25: error: expected constructor, destructor, or type conversion before ‘(’ token
     Student::setLastName(ln) { this->firstName = ln; }
                         ^
Student.cpp:25:26: error: ISO C++ forbids declaration of ‘setAge’ with no type [-fpermissive]
     Student::setAge(int a) { this->age = a; }
                          ^
Student.cpp:25:5: error: prototype forint Student::setAge(int)’ does not match any in class ‘Student’
     Student::setAge(int a) { this->age = a; }
     ^~~~~~~
In file included from Student.cpp:1:0:
Student.h:38:10: error: candidate is: void Student::setAge(int)
     void setAge(int a);
          ^~~~~~
Student.cpp:26:24: error: expected constructor, destructor, or type conversion before ‘(’ token
     Student::setAddress(add) { this->address = add; }
                        ^
Student.cpp:27:21: error: expected constructor, destructor, or type conversion before ‘(’ token
     Student::setCity(c) { this->city = c; }
                     ^
Student.cpp:28:22: error: expected constructor, destructor, or type conversion before ‘(’ token
     Student::setPhone(p) { this->phone = p; }
Your method definitions are missing the return type.
It looks like you aren't specifying the return type of your functions.
1
2
3
 
Student::setAge(int); //return type is void
int Student::setAge(int); //return type is int. 


You'll need to change how they are defined in your header and in your cpp file
Thank you!

I've updated the functions with return types, function argument types in Student.cpp and after including Student.cpp in the main program it works perfectly fine now.

But I'm curious, why do I have to add #include <string> to Student.h and #include <iostream> to Student.cpp, considering that these are also included in main.cpp?

What happens when compiler reads these files? Is it going to #include <iostream> twice because of Student.cpp or it is smart enough to not double include it?
Put simply, Student.h needs <string>, because it uses the std::string class. Anywhere you include that file, will also need <string>, or the compiler won't understand the header. Including it in Student.h means you can include Student.h anywhere you like, and know that it includes all the necessary definitions.

Similarly, Student.cpp needs <iostream>, because it uses std::cout, and that's defined in <iostream>. Without that include statement, the compiler won't understand what std::cout is.

What main.cpp includes is irrelevant, since Student.cpp doesn't #include main.cpp or vice versa. They're entirely separate translation units, and when the compiler compiles Student.cpp it neither knows nor cares what's in main.cpp.

iostream will have multiple inclusion guards, just like your Student.h, so it doesn't matter how many times it gets included in a single translation unit; its contents will only be compiled once in each translation unit.
But I'm curious, why do I have to add #include <string> to Student.h and #include <iostream> to Student.cpp, considering that these are also included in main.cpp?

The reason for this is the way compilation works.
(I crossed out the part which doesn't match the situation in your code.)
(Note: if you included <string> in Student.h you wouldn't have to include it in main.cpp and Student.cpp which you'll see why.)

The compiler compiles every .cpp file individually into what is known as object files (they go with .o extension)

The linker then takes all the .o files and links them into a final product that is .exe file (or an ELF binary which the equivalent if you're in GNU/Linux)

In the real world using g++ this would look like this:
1
2
3
4
5
//the -c option tells g++ to produce .o files.
//the -o option tells g++ to link .o files and produce a binary
g++ main.cpp -c main.o
g++ Student.cpp -c Student.o
g++ Student.o main.o -o program.exe

Note that each of these lines means g++ executes 3 times separately.
For example, the first call to g++ opens the main.cpp file, processes it and produces main.o file but it doesn't even know that Student.cpp exists or that it'll be part of the main program! Therefore, if you do #include <string> in Student.cpp this is of absolutely no concern to main.cpp whatsoever.

If you put #include <string> in Student.h which is included by both main.cpp and Student.cpp then it's an entirely different story.
#include basically inserts text inside the .cpp file. g++ does this twice, once inside main.cpp and another time for Student.cpp when they are respectively compiled.

You might be confused about header guards.
As in, you may believe you need them because you're doing #include <Student.h> in both main.cpp and Student.cpp
But this is not so since they are compiled separately.

As a matter of fact, you would do just fine without header guards here since you've only used #include <Student.h> once in each file!
The header guards are only there to prevent you to call #include <Student.h> in the same file
Last edited on
Topic archived. No new replies allowed.