c ++:'{'标记之前的预期类名

时间:2014-05-07 02:02:40

标签: c++ netbeans

当我尝试运行此代码时:

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;
};

我收到这些错误:

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();

这三个错误让我感到困惑。如果Instructor类派生自Person,并且Person内的性别字段受到保护,那么为什么我会收到error: ‘gender’ was not declared in this scope以及error: cannot call member function ‘virtual void Person::print()’ without object

我觉得我在这里做了一些明显错误的事情,例如错误地包含文件或类似的东西。任何帮助表示赞赏。

5 个答案:

答案 0 :(得分:8)

您必须在person.h中包含instructor.h,否则令牌Person对于编译器是未知的。执行此操作时,请务必从person.h中删除instructor.cpp。否则,您将收到重新声明错误。但通常的做法是在头文件中使用#ifdef指令以防止多次包含。比如person.h

#ifndef PERSON_H
#define PERSON_H


/// class definition and other code


#endif //PERSON_H

或者您可以在VC ++中使用#pragma once

另一个错误是您没有正确初始化Person Instructor部分。在构造函数中:

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;
}

这样做

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

答案 1 :(得分:2)

几个问题:

  1. 当您定义Instructor课程时,您的Person课程尚未定义。您应该在#include "Person.h"开头Instructor.h,这会导致第二个问题......
  2. 您的标题不受双重包含的保护(这是您在上面的评论中看到的错误)。要解决这个问题,你需要一个包含守卫:

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

    第二次包含此文件时,PERSON_H已定义,因此#ifndef#endif之间的内容将被忽略。

  3. 您正在错误地调用基类构造函数。正确的语法是:

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

    你正在做什么(在构造函数体中编写Person(n, d, g);)将编译,因为如果你没有显式调用基类构造函数,编译器将尝试为你调用无参数的默认构造函数,并在你的case,Person碰巧有一个可以调用的默认构造函数(如果Person没有不带参数的构造函数,那么你会得到一个编译错误)。但是,该语句的作用只是创建一个临时的Person对象,该对象在语句结束时被破坏,而不是调用基类构造函数。

    这种语法(称为成员初始化列表)也可用于初始化其他类成员,实际上是这样做的首选方式:

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

答案 2 :(得分:1)

每次编译器遇到#include "FileName.h"预处理程序指令时,编译器都会尝试重新加载 - 我相信,重新定义 - 包含的类。这将导致编译时错误。您可以详细了解包含警卫包装器#ifndef here

为了&#34;守卫&#34;与此相反,我们使用包含警卫 - ,它必须出现在您的头文件中的任何代码之前。

例如:

#ifndef CLASSIDENTIFIER_H // Capitalized letters are convention (see below)
#define CLASSIDENTIFIER_H

#include <iostream>
#include <cstdlib>

public ClassIdentifier
{
   // Class Member Declarations
};
#endif

#ifndef代表&#34;如果没有定义&#34;。以下标识符 - 在所有大写字母中没有任何理由,除了&#39;以及它是如何完成的#39; - 按惯例也是根据类名命名的(这使得编译器能够检查许多事情,主要是确保 - 如果每个人都遵循约定 - 没有包含,引用或定义其他同名的类该计划。

从逻辑上讲,可以推断出接下来的两个包括警卫代表&#34;定义&#34;并且&#34;如果没有定义则结束&#34;。

如果您在课程声明结束后立即加入#endif,例如};#endif(见上文)这也会导致编译时错误,而且可能不会很明显(尽管我认为编译器很清楚它产生的错误信息)。

我包含的其他代码当然只是为了熟悉和演示可能的内容。

答案 3 :(得分:0)

需要修改一些事项:

  1. Instructor.h需要#include "Person.h"。这是必需的,因此Instructor了解它继承的内容。如果您将Instructor.cpp移至Instructor.h,而Instructor.cpp已包含Instructor.h,则不需要此Person
  2. 我不确定您是否打算将Person.cpp作为抽象基类,但我在Person.h中看不到Person或任何成员函数的任何实现}。即使你希望Person() {};是一个抽象基类,你也需要给构造函数赋一个函数体,即使它是空的。

    Person::print

  3. 如果没有实施,您就会在Instructor::print中致电Person

  4. 使用继承时,需要使用成员初始化列表来调用基类构造函数来初始化基类的成员变量。在两个教师构造函数中,使用函数体中的Instructor::Instructor() : Person(), salary(0) { }构造函数,因为您当前不会产生所需的结果。
    此外,使用初始化列表更有效,并且可以接受用于设置类自己的成员变量的对流。

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

    {{1}}

答案 4 :(得分:-1)

它只是在Instructor.cpp中包含头文件的顺序吗?您必须先包含Person.h,然后再包含Instructor.h。多数民众赞成。