例如,使用以下代码:
#include <iostream>
#include <string>
int main()
{
print("Hello!");
}
void print(std::string s) {
std::cout << s << std::endl;
}
尝试构建时,我得到以下内容:
program.cpp: In function ‘int main()’:
program.cpp:6:16: error: ‘print’ was not declared in this scope
这是有道理的。
那么为什么我可以在一个结构中进行类似的概念,但不会因此而大喊大叫呢?
struct Snake {
...
Snake() {
...
addBlock(Block(...));
}
void addBlock(Block block) {
...
}
void update() {
...
}
} snake1;
我不仅没有得到警告,而且程序实际编译!没有错误!这只是结构的本质吗?这里发生了什么事?显然,在声明方法之前调用了addBlock(Block)
。
答案 0 :(得分:15)
C ++中的struct
实际上是class
定义,其内容为public
,除非另有说明,包括protected:或private:section。
当编译器看到class
或struct
时,它首先会消化块({}
)中的所有声明,然后再对它们进行操作。
在常规方法的情况下,编译器还没有看到声明的类型。
答案 1 :(得分:13)
C ++标准3.4.1:
0.4:
在全局范围内使用的名称,在任何函数,类或之外 用户声明的命名空间,应在全局使用之前声明 范围。
这就是为什么在上述声明之前不能使用全局变量和函数的原因。
0.5:
在定义之外的用户声明的命名空间中使用的名称 任何功能或类别在使用前应予以声明 命名空间或在封闭其命名空间的命名空间中使用之前。
同样的事情只是再写一次,因为.4段明确地限制了它对全球&#34;的说法,这一段现在说&#34;顺便说一句,它的真实以及名人们...... #34;
0.7:
在成员之外定义类X的名称 函数体或嵌套类的定义29应在其中一个中声明 通过以下方式: - 在X类中使用之前或成为一个成员 基类X(10.2),或者 - 如果X是类Y(9.7)的嵌套类, 在Y中定义X之前,或者应该是基类的成员 Y(这个查找依次适用于Y的封闭类,从开始 使用最里面的封闭类),30或 - 如果X是本地类 (9.8)或者是本地类的嵌套类,在定义之前 包含X类定义的块中的类X,或者 - 如果X是a 命名空间N的成员,或者是一个类的嵌套类 N的成员,或者是本地类或本地的嵌套类 在定义之前,是N的成员的函数的类 名称空间N中的类X或N的封闭名称空间之一。
我认为这说明了所有不在cpu执行代码中的代码(例如声明性代码)。
最后是有趣的部分:
3.3.7班级范围[basic.scope.class]
1以下规则描述了在类中声明的名称范围。
1)潜在的范围 在类中声明的名称不仅包含声明性区域 遵循名称的声明,但也包括所有功能 非静态数据成员的主体,支撑或平等初始化器,以及 该类中的默认参数(包括嵌套中的这些内容) 类)。
2)S类中使用的名称N应指相同的名称 声明在其背景下以及在完成时重新评估 S的范围违反此规则不需要诊断。
3) 如果在类中重新排序成员声明会产生备用有效 根据(1)和(2)的程序,该程序是不正确的,没有诊断 必需的。
特别是,在最后一点,他们使用否定的方式来定义&#34;任何排序都是可能的&#34;因为如果重新排序会改变查找,那么就会出现问题。这是一种消极的说法,你可以对任何东西进行重新排序,没关系,它不会改变任何东西&#34;。
有效地说,在一个类中,声明是以两阶段编译方式查找的。 p>
答案 2 :(得分:5)
&#34; 为什么 我可以在结构中执行类似的概念,但不会因此而大喊大叫吗?&#34;
在struct
或class
定义中,您 向一个班级展示 更容易理解,搜索和维护/更新该API,如果它出现在:
对于可预测的订单,人们有自己的风格,并且有一些&#34;艺术&#34;涉及,但是例如我最多使用一次访问说明符,并且public
在protected
之前始终private
,然后在我通常放typedef
s const
之内} data,constructors,destructors,mutating / non-const functions,const
functions,static
s,friend
s ....
为了最大限度地减少混乱,如果一个函数在类中定义,它也可能没有事先声明。两者都倾向于混淆界面。
这与不属于某个类的成员的函数不同 - 喜欢自上而下编程的人确实使用函数声明并在文件的后面隐藏定义 - 其中:
喜欢自下而上的编程风格的人不会因为被迫在课堂上单独声明或放弃通过访问说明符进行分组的经常冲突的做法而感到欣慰
类在统计上更有可能具有许多非常短的函数,主要是因为它们提供封装并包含大量简单的数据成员访问或提供运算符重载,转换运算符,隐式构造函数和其他便利功能。 ; t与非OO,非成员函数相关。这使得声明和定义的持续强制分离对于许多类来说更加痛苦(在公共接口中并非如此,其中定义可能位于单独的文件中,但对于例如支持当前转换单元的匿名命名空间中的类来说肯定是如此)。
最佳做法是让课程不要填充广泛的界面...你通常需要一个功能核心,然后是一些自由支配的便利功能,之后值得考虑可以添加为非 - 成员函数。 std::string
经常声称拥有太多会员功能,但我个人认为这是非常合理的。尽管如此,这也不同于声明库接口的头文件,其中可以预期详尽的功能被挤在一起,使得偶数inline
实现的分离更加可取。