C++:“{”标记之前的预期类名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23507482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
c++: expected class-name before '{' token
提问by user2628156
When I try to run this code:
当我尝试运行此代码时:
Instructor.cpp:
导师.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:
导师.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:
人.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
?
所有这三个错误都让我感到困惑。如果 Instructor 类是从 Person 派生的,并且在 Person 中,性别字段是受保护的,那么为什么我会收到error: ‘gender' was not declared in this scope
,以及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.
我觉得我在这里做了一些明显错误的事情,例如错误地包含文件或类似的东西。任何帮助表示赞赏。
回答by Rakib
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-declarationerror. But common practice is to use #ifdef
directives in header files to prevent multiple inclusion. like in person.h
您必须包含person.h
in instructor.h
,否则Person
编译器不知道该令牌。执行此操作时,请确保person.h
从instructor.cpp
. 否则你会得到重新声明错误。但通常的做法是#ifdef
在头文件中使用指令来防止多重包含。像person.h
#ifndef PERSON_H
#define PERSON_H
/// class definition and other code
#endif //PERSON_H
or you can use #pragma once
in VC++.
或者您可以#pragma once
在 VC++ 中使用 。
Another error is you are not initializing Person
portion of Instructor
correctly. In the constructor :
另一个错误是您没有正确初始化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;
}
do it like this
像这样做
Instructor::Instructor(string n, string d, string g, int s): Person(n,d,g), salary(s)
{ }
回答by T.C.
Several issues:
几个问题:
- At the time you defined your
Instructor
class, yourPerson
class isn't defined yet. You should#include "Person.h"
at the start ofInstructor.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 (ifPerson
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 temporaryPerson
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) { }
- 在您定义
Instructor
类时,您的Person
类尚未定义。你应该#include "Person.h"
在开头Instructor.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) { }
回答by Thomas
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 guardsor the wrapper #ifndef, here.
每次编译器遇到#include "FileName.h"
预处理器指令时,编译器都会尝试重新加载 - 我相信,重新定义 - 包含的类。这将导致编译时错误。你可以阅读更多详细介绍一下包括警卫或包装的#ifndef,在这里。
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.
该#ifndef
代表“如果没有定义”。以下标识符 - 除了“这就是它的完成方式”之外,所有大写都无缘无故 - 按照约定也根据类名命名(这使编译器能够检查许多事情,主要确保 - 如果每个人都遵循约定- 程序中没有包含、引用或定义其他同名类。
Logically, one can deduce that the next two include guardsstand 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).
如果您#endif
在类声明结束后立即包含您的内容,例如};#endif
(见上文),这也会导致编译时错误,并且可能不会很明显(不过,我认为编译器对由此产生的错误非常清楚信息)。
The other code I included is, of course, just for the sake of familiarity and a demonstration of what is possible.
当然,我包含的其他代码只是为了熟悉和演示可能的内容。
回答by Fred Thomsen
A few things need to be fixed:
有几件事需要解决:
Instructor.h
needs to have#include "Person.h"
. It is needed there soInstructor
understands what it inherits from. No need for this include to exist inInstructor.cpp
if you move it toInstructor.h
asInstructor.cpp
hasInstructor.h
included.I am not sure if you intended for
Person
to be an abstract base class, but I don't see aPerson.cpp
or any implementation of any member functions inPerson.h
. Even if you wantPerson
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
inInstructor::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) { }
Instructor.h
需要有#include "Person.h"
。那里需要它,以便Instructor
了解它继承的内容。Instructor.cpp
如果您将其移动到Instructor.h
asInstructor.cpp
hasInstructor.h
包括,则不需要此包含。我不确定您是否打算
Person
成为抽象基类,但我Person.cpp
在Person.h
. 即使你想Person
成为一个抽象基类,你也需要给构造函数一个函数体,即使它是空的。Person() {};
您
Person::print
在Instructor::print
没有实现的情况下调用。使用继承时,需要利用成员初始化列表,调用基类构造函数来初始化基类的成员变量。在这两个 Instructor 构造
Person
函数中,在函数体中使用当前的构造函数不会导致预期的结果。
此外,使用初始化列表更有效,并且可以接受设置类自己的成员变量的对流。Instructor::Instructor() : Person(), salary(0) { }
Instructor::Instructor(string n, string d, string g, int s) : Person(n, d, g), salary(s) { }
回答by Ramana Babu
Isnt it just the order of including header files in Instructor.cpp? You will have to include Person.h first and then Instructor.h. Thats It.
不就是Instructor.cpp 中包含头文件的顺序吗?您必须首先包含 Person.h,然后包含 Instructor.h。就是这样。