C++:在"{"标记之前应具有类名

  • 本文关键字:C++ c++ netbeans
  • 更新时间 :
  • 英文 :


当我尝试运行这段代码时:

讲师.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;
}

讲师:

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

人:

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

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

我觉得我在这里做错了什么,例如错误地包含文件或类似的事情。 任何帮助,不胜感激。

你必须

instructor.h中包含person.h,否则编译器不知道令牌Person。执行此操作时,请确保从instructor.cpp中删除person.h。否则,您将收到重新声明错误。但通常的做法是在头文件中使用 #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. 定义Instructor类时,尚未定义Person类。你应该在Instructor.h开头#include "Person.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);(将编译,因为如果您不显式调用基类构造函数,编译器将尝试为您调用无参数默认构造函数,在您的情况下,Person恰好有一个可以调用的默认构造函数(如果Person没有不带参数的构造函数, 你将收到编译错误(。但是,该语句的作用只是创建一个在语句末尾被破坏的临时Person对象,而不是调用基类构造函数。

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

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

每次编译器遇到 #include "FileName.h" 预处理器指令时,编译器都会尝试重新加载 - 我相信,重新定义 - 包含的类。这将导致编译时错误。您可以在此处阅读有关包含防护装置或包装器 #ifndef 的更多详细信息。

为了"防范"这种情况,我们使用包含防护 - 它必须出现在头文件中的任何代码之前

例如:

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

#ifndef代表"如果未定义"。以下标识符 - 在所有大写字母中,除了"这就是它是如何完成的"之外没有其他原因 - 按照惯例也是根据类名命名的(这使编译器能够检查许多事情,主要是确保 - 如果每个人都遵循约定 - 程序中没有包含,引用或定义其他同名的类。

从逻辑上讲,可以推断出接下来的两个包括守卫代表"定义"和"如果未定义则结束"。

如果您在集体声明结束后立即包含您的#endif,例如 };#endif(见上文(这也会导致编译时错误,并且可能不明显(尽管我认为编译器对其生成的错误消息非常清楚(。

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

需要修复一些问题:

  1. Instructor.h需要有#include "Person.h". 那里需要它,以便Instructor了解它继承了什么。 如果您将其移动到Instructor.h,则无需在Instructor.cpp中存在此包含Instructor.cpp因为它Instructor.h包含。
  2. 我不确定您是否打算将Person作为一个抽象的基类,但我在Person.h中没有看到任何成员函数的Person.cpp或任何实现。 即使希望Person是一个抽象基类,即使构造函数为空,也需要为构造函数提供函数体。

    Person() {};

  3. 您在Instructor::print中调用Person::print,而没有实现。

  4. 使用继承时,需要使用成员初始化列表,该列表调用基类构造函数来初始化基类的成员变量。 在这两个 Instructor 构造函数中,按当前方式在函数体中使用 Person 构造函数不会产生所需的结果。
    此外,使用初始化列表更有效,并且是设置类自己的成员变量的公认对流。

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

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

不就是在 Instructor.cpp 中包含头文件的顺序吗?您必须先包括 Person.h,然后包含 Instructor.h。就是这样。

相关内容

  • 没有找到相关文章

最新更新