Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++: expected class-name before '{' token

Tags:

c++

netbeans

When I try to run this code:

Instructor.cpp:

#include "Instructor.h"
#include "Person.h"

using std::string;

Instructor::Instructor() {
    Person();
    salary = 0;
}

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

void Instructor::print() {
    if (gender == "M")
        std::cout << "Mr. ";
    else
        std::cout << "Ms. ";
    Person::print();
    std::cout << "    Instructor, Salary: " << salary << std::endl;
}

Instructor.h:

#include <iostream>
#include <string>

class Instructor: public Person 
{
public:
    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.

like image 383
user2628156 Avatar asked May 07 '14 02:05

user2628156


2 Answers

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) 
{   }
like image 131
Rakib Avatar answered Sep 30 '22 19:09

Rakib


Several issues:

  1. 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...
  2. 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.

  3. 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) { }
    
like image 37
T.C. Avatar answered Sep 30 '22 19:09

T.C.