Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams Instructor(); Instructor(std::string n, std::string d, std::string g, int s); virtual void print(); protected: int salary;

Person.h:

#include <iostream>
#include <string>
class Person
public:
    Person();
    Person(std::string n, std::string d, std::string g);
    virtual void print();
protected:
    std::string name;
    std::string dob;
    std::string gender;

I receive these errors:

In file included from Instructor.cpp:1:0:
Instructor.h:5:1: error: expected class-name before ‘{’ token
Instructor.cpp: In member function ‘virtual void Instructor::print()’:
Instructor.cpp:16:6: error: ‘gender’ was not declared in this scope
  if (gender == "M")
Instructor.cpp:20:16: error: cannot call member function ‘virtual void Person::print()’ without object
  Person::print();

All three of these errors are confusing me. If the Instructor class was derived from Person, and within Person the gender field is protected, then why am I receiving error: ‘gender’ was not declared in this scope, as well as error: cannot call member function ‘virtual void Person::print()’ without object?

I feel like I'm doing something obviously wrong here, such as including the files incorrectly or something like that. Any help is appreciated.

I tried that, and I get the error: In file included from Instructor.cpp:2:0: Person.h:4:7: error: redefinition of ‘class Person’ class Person ^ In file included from Instructor.h:4:0, from Instructor.cpp:1: Person.h:4:7: error: previous definition of ‘class Person’ – user2628156 May 7, 2014 at 2:05 If you already have that, then you likely have a double include if there aren't include guards (you're including Person.h in Instructor.h and Instructor.cpp, which is also getting the copy from Instructor.h) – aruisdante May 7, 2014 at 2:06

You have to include person.h in instructor.h, otherwise the token Person is unknown to compiler. And when you do this, make sure you remove person.h from instructor.cpp. Otherwise you will get re-declaration error. But common practice is to use #ifdef directives in header files to prevent multiple inclusion. like in person.h

#ifndef PERSON_H
#define PERSON_H
/// class definition and other code
#endif //PERSON_H

or you can use #pragma once in VC++.

Another error is you are not initializing Person portion of Instructor correctly. In the constructor :

Instructor::Instructor(string n, string d, string g, int s) {
  Person(n, d, g); // this will create a temporary `Person` object instead of initializing base part and 
                   // default constructor of `Person` will be used for this `Instructor` object
  salary = s;

do it like this

Instructor::Instructor(string n, string d, string g, int s): Person(n,d,g), salary(s) 
{   }
                I did this, now there is only one #include person.h in instructor.h and nowhere else, however I am getting In file included from main.cpp:15:0: Person.h:4:7: error: previous definition of ‘class Person’  class Person        ^ In file included from Instructor.h:4:0,                  from main.cpp:17: Person.h:4:7: error: redefinition of ‘class Person’  class Person        ^ In file included from main.cpp:15:0: Person.h:4:7: error: previous definition of ‘class Person’  class Person
– user2628156
                May 7, 2014 at 2:13
  • At the time you defined your Instructor class, your Person class isn't defined yet. You should #include "Person.h" at the start of Instructor.h, which leads to the second issue...
  • Your headers are not protected against double includes (which is the error you see in your comment above). To fix this, you need an include guard:

    #ifndef PERSON_H
    #define PERSON_H
    class Person {
         // ...
    #endif
    

    The second time this file is included, PERSON_H is already defined, so what's between the #ifndef and the #endif will be ignored.

  • You are calling the base class constructor incorrectly. The correct syntax is:

    Instructor::Instructor(string n, string d, string g, int s) : Person(n, d, g){
        salary = s;
    

    What you are doing (writing Person(n, d, g); in the constructor body) will compile, because if you do not explicitly call the base class constructor, the compiler will try to call the parameterless default constructor for you, and in your case, Person happens to have a default constructor that can be called (if Person does not have a constructor that takes no parameters, you'll get a compile error). However, the effect of that statement is simply to create a temporary Person object that gets destructed at the end of the statement, not call the base class constructor.

    This syntax (called a member initialization list) can also be used to initialize other class members, and in fact is the preferred way of doing so:

    Instructor::Instructor(string n, string d, string g, int s) : Person(n, d, g), salary(s) { }
                    @T.C. " but it's effect is to create a temporary Person object that gets destructed at the end of that statement." is wrong. It will give error. Base class constructor can be called only in initializer list.
    – Rakib
                    May 7, 2014 at 2:39
                    @RakibulHasan It won't be parsed as a base class constructor call. It would be parsed as a temporary object creation - that's the whole point (in this case, the base class isn't abstract, so it would compile just fine). Example.
    – T.C.
                    May 7, 2014 at 2:53
                    @RakibulHasan That's a different problem - A(x); gets parsed as declaring a variable called x with type A, equivalent to A x;, which then causes the redefinition error; A(x, y); gets parsed as creating a temporary A object, calling the constructor with parameters x and y, which is then thrown away.
    – T.C.
                    May 7, 2014 at 3:46
                    @RakibulHasan - calling on your expertise, here. Isn't saying "creating a temporary [parent] object" superfluous and incorrect? First, all memory consumption is temporary (everything is thrown away at some point). Second, I am not sure that statement that T.C. made accurately reflects what happens. The parent constructor is called as a part of creating the derived class and the only object that is created is a child object with attributes derived from the parent and specified by the child; however, in order to properly handle the parent portion of the object, the parent destructor is called?
    – Thomas
                    May 7, 2014 at 11:37
    

    Each time the compiler encounters the #include "FileName.h" preprocessor directive, the compiler attempts to re-load - and, I believe, redefine - the included class. This will result in a compile-time error. You can read more in detail about include guards or the wrapper #ifndef, here.

    In order to "guard" against this, we use include guards - which must appear before any of your code in your header file.

    For example:

    #ifndef CLASSIDENTIFIER_H // Capitalized letters are convention (see below)
    #define CLASSIDENTIFIER_H
    #include <iostream>
    #include <cstdlib>
    public ClassIdentifier
       // Class Member Declarations
    #endif
    

    The #ifndef stands for "if not defined". The following identifier - in all capitals for no reason other than 'that's how it's done' - is by convention also named according to the class name (this enables the compiler to check a number of things, primarily ensuring that - if everyone follows the convention - that no other class of the same name has been included, referenced, or defined in the program.

    Logically, one can deduce that the next two include guards stand for "define" and "end if not defined".

    If you include your #endif immediately after the close of your class declaration, e.g. };#endif(see above) this will also result in a compile-time error and one that may not be readily apparent (though, I think the compiler is pretty clear with its resulting error message).

    The other code I included is, of course, just for the sake of familiarity and a demonstration of what is possible.

  • Instructor.h needs to have #include "Person.h". It is needed there so Instructor understands what it inherits from. No need for this include to exist in Instructor.cpp if you move it to Instructor.h as Instructor.cpp has Instructor.h included.
  • I am not sure if you intended for Person to be an abstract base class, but I don't see a Person.cpp or any implementation of any member functions in Person.h. Even if you want Person to be an abstract base class, you need to give a function body to the constructor even if it is empty.

    Person() {};

  • You are calling Person::print in Instructor::print without it having an implementation.

  • When using inheritance, you need to utilize member initialization list which calls the base class constructor to initialize the base class's member variables. In both Instructor constructors, using the Person constructors in the function body as you are currently doesn't lead to the desired result.
    Furthermore, using initialization lists is more efficient and the accepted convection for setting the class's own member variables.

    Instructor::Instructor() : Person(), salary(0) { }

    Instructor::Instructor(string n, string d, string g, int s) : Person(n, d, g), salary(s) { }

  • Having the correctness of the program depend on the order in which header files are included is very bad form. Headers should always be self-sufficient. – T.C. May 7, 2014 at 7:14

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.

  •