当我尝试运行这段代码时:
讲师.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)
{ }
几个问题:
- 定义
Instructor
类时,尚未定义Person
类。你应该在Instructor.h
开头#include "Person.h"
,这导致了第二个问题...... -
您的标头不受双重包含保护(这是您在上面的评论中看到的错误(。要解决此问题,您需要一个包含保护:
#ifndef PERSON_H #define PERSON_H class Person { // ... }; #endif
第二次包含此文件时,
PERSON_H
已经定义,因此#ifndef
和#endif
之间的内容将被忽略。 -
您错误地调用了基类构造函数。正确的语法是:
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
(见上文(这也会导致编译时错误,并且可能不明显(尽管我认为编译器对其生成的错误消息非常清楚(。
当然,我包含的其他代码只是为了熟悉和演示可能的内容。
需要修复一些问题:
-
Instructor.h
需要有#include "Person.h"
. 那里需要它,以便Instructor
了解它继承了什么。 如果您将其移动到Instructor.h
,则无需在Instructor.cpp
中存在此包含Instructor.cpp
因为它Instructor.h
包含。 -
我不确定您是否打算将
Person
作为一个抽象的基类,但我在Person.h
中没有看到任何成员函数的Person.cpp
或任何实现。 即使希望Person
是一个抽象基类,即使构造函数为空,也需要为构造函数提供函数体。Person() {};
-
您在
Instructor::print
中调用Person::print
,而没有实现。 -
使用继承时,需要使用成员初始化列表,该列表调用基类构造函数来初始化基类的成员变量。 在这两个 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。就是这样。