类作用域中名字查找的思考(《C++ primer》第四版P382)

1、问题的引入

1).观察以下第一块代码:

#include <iostream>
using namespace std;
class Screen{
public:
        void test(){
                dummy_fcn( );
        }

        void dummy_fcn( ){
        }
};

此代码编译无错误。。。。。。。。。。。。。。。

2).再看以下第二块代码:

#include <iostream>
using namespace std;
void test(){
        dummy_fcn( );
}
void dummy_fcn( ){
}

此代码编译出错。。。。。。。。。。。。。

3).再看第三块代码:

#include <iostream>
using namespace std;
void dummy_fcn( ){
}
void test(){
        dummy_fcn( );
}

此代码编译也无错误。。。。。

4).第四块代码:

#include <iostream>
using namespace std;
class Screen{
public:
        typedef std::string::size_type index;

        void test(){
                dummy_fcn( );
        }

        void dummy_fcn( ){
                cursor = width * height;
        }
private:
        index cursor;
        index height, width;
};

此代码编译并无错误。。。。。。。。。。。。。。。。。。。。。。

5).第五块代码:

#include <iostream>
using namespace std;
class Screen{
public:
        void test(){
                dummy_fcn( );
        }
        void dummy_fcn( ){
                cursor = width * height;
        }
private:
        index cursor;
        index height, width;
        typedef std::string::size_type index;
};

此代码编译出错。。。。。。。。。。。

2、发现

发现1:对比第1、2、3块代码,我们发现在类中,名字查找是比较特殊的。对于普通的函数名字,编译器只会从其之前的地方查找是否声明,若无声明就报错(如代码2)。。而对于类中的名字来说,编译器将会在整个类作用域中进行查找(如代码1),若找不到,会进一步在整个类的定义之前进行查找。

发现2:对比第4、5块代码,其不同之处仅仅在于index类型变量的定义位置。可知,编译器在对类的定义进行编译时,并不会在整个类作用域内查找类型的定义(此例中index的定义)。

3、思考

以上的两点发现其实和类定义的“两步编译”有关。。见《C++ primer》第4版中P382,

“类定义实际上是在两个阶段中处理的:

(1)首先,编译成员声明;

(2)只有在所有成员出现之后,才编译它们的定义本身。

其中发现2对应“两步编译”中的第一步(《C++ primer》中称为类成员声明的名字查找),而发现1对应第二步(《C++ primer》中称为类成员定义中的名字查找)。

3.1第一步编译的思考

在第一步编译所有成员声明中,不会检查成员函数定义中的函数调用(如发现2中的例子)。此时只会对成员声明中的类名是否定义进行检查(如上例中的index),这种检查会分为两步:

1)在类中该类名使用之前进行查找

2)在整个类定义之前进行查找

3.2第二步编译的思考

在第二步编译它们的定义时,会进一步检查成员函数中的函数调用(如发现1中的例子)。此时的检查会分为三步:

1)在成员函数局部作用域中进行查找

2)在整个类定义域中进行查找。之所以能够在整个类定义域中进行查找,是因为经过了第一步的对所有类成员声明的定义。这也是和普通名字查找不同的地方(如发现1中的例子)

3)在这个类成员函数定义之前(这里不仅仅指类定义之前,因为类成员函数可能是在类外部)进行查找

时间: 2024-12-25 18:41:39

类作用域中名字查找的思考(《C++ primer》第四版P382)的相关文章

C++ Primer笔记3_默认实参_类初探_名字查找与类的作用域

1.默认函数实参 在C++中,可以为参数指定默认值,C语言是不支持默认参数的,Java也不支持! 默认参数的语法与使用: (1)在函数声明或定义时,直接对参数赋值.这就是默认参数: (2)在函数调用时,省略部分或全部参数.这时可以用默认参数来代替. 注意事项: (1)函数默认值只能赋值一次,或者是在声明中,或者是在定义中,都可以. (2)默认参数定义的顺序为自右到左.即如果一个参数设定了缺省值时,其右边的参数都要有缺省值.比如int f(int a, int b=1,int c=2,int d=

C++术语——类【C++primer 第四版】

abstract data type(抽象数据类型): 使用封装来隐藏其实现的数据结构,允许使用类型的程序员抽象地考虑该类型做什么,而不是具体地考虑类型如何表示.C++中的类可以用来定义抽象数据类型. access label(访问标号): public.private.protected,指定后面的成员可以被类的使用者访问或者只能被类的友元和成员访问.每个标号为在该标号到下一个标号之间声明的成员设置访问保护.标号可以出现多次. class(类): C++中定义抽象数据类型的一种机制,可以有数据

OOP3(继承中的类作用域/构造函数与拷贝控制/继承与容器)

当存在继承关系时,派生类的作用域嵌套在其基类的作用域之内.如果一个名字在派生类的作用域内无法正确解析,则编译器将继续在外层的基类作用域中寻找该名字的定义 在编译时进行名字查找: 一个对象.引用或指针的静态类型决定了该对象的哪些成员是可见的,即使静态类型与动态类型不一致: 1 #include <iostream> 2 using namespace std; 3 4 class A{ 5 public: 6 // A(); 7 // ~A(); 8 ostream& print(ost

面向对象程序设计——抽象基类,访问控制与继承,继承中的类作用域,拷贝函数与拷贝控制

一.抽象基类 1)纯虚函数 和普通的虚函数不同,一个纯虚函数无须定义.我们通过在函数体的位置(即在声明语句的分号之前)书写=0就可以将一个虚函数说明为纯虚函数.其中,=0只能出现在类内部的虚函数声明语句处. 值得注意的是,我们也可以为纯虚函数提供定义,不过函数体必须定义在类的外部.也就是说,我们不能在类的内部为一个=0的函数提供函数体. 2)含有纯虚函数的类是抽象基类 含有(或者未经覆盖直接继承)纯虚函数的类是抽象基类.抽象基类负责定义接口,而后续的其他类可以覆盖该接口.我们不能直接创建一个抽象

15.5——继承情况下的类作用域

继承情况下的类作用域: 在继承的情况下,派生类的作用域嵌套在基类作用域的下. 先在派生类的作用域范围内查找,要是没找到,接着在外围的基类作用域中查找. 1. 名字查找在编译时发生 (1)对象,引用或指针的静态类型决定了其所能作用的成员,即使是当动态类型和静态类型可能不一样时也满足 (2)例如使用基类的指针就不能去访问派生类的成员. 2. 名字冲突与继承 (1)当基类和派生类的成员同名时,基类的成员在直接访问时将被屏蔽. (2)可以采用域作用符::来访问被屏蔽的成员. (3)最好不要有基类和派生类

C++ Primer 学习笔记_17_类与数据抽象(3)_类作用域

C++ Primer 学习笔记_17_类与数据抽象(3)_类作用域 引言: 每个类都定义了自己的新作用域与唯一的类型.即使两个类具有完全相同的成员列表,它们也是不同的类型.每个类的成员不同与任何其他类(或任何其他作用域)的成员. 一.类作用域中的名字查找 1)首先,在使用该名字的块中查找名字的声明.只考虑在该项使用之前声明的名字. 2)如果在1)中找不到,则在包围的作用域中查找. 如果找不到任何声明,则出错. 类的定义实际上是在两个阶段中处理: 1)首先,编译器声明: 2)只有在所有成员出现之后

C++ Primer 学习笔记_69_面向对象编程 --继承情况下的类作用域

面向对象编程 --继承情况下的类作用域 引言: 在继承情况下,派生类的作用域嵌套在基类作用域中:如果不能在派生类作用域中确定名字,就在外围基类作用域中查找该名字的定义. 正是这种类作用域的层次嵌套使我们能够直接访问基类的成员,就好像这些成员是派生类成员一样: Bulk_item bulk; cout << bulk.book() << endl; 名字book的使用将这样确定[先派生->后基类]: 1)bulk是Bulk_item类对象,在Bulk_item类中查找,找不到名

C++ Primer 学习笔记_50_类与数据抽象 --类作用域

类 --类作用域 引言: 每个类都定义了自己的新作用域与唯一的类型.即使两个类具有完全相同的成员列表,它们也是不同的类型.每个类的成员不同与任何其他类(或任何其他作用域)的成员. class First { public: int memi; double memd; }; class Second { public: int memi; double memd; }; First obj1; Second obj2 = obj1; //Error 1.使用类的成员 在类作用域之外,成员只能通过

C++ Primer 学习笔记_69_面向对象编程 -继承景况下的类作用域

面向对象编程 --继承情况下的类作用域 引言: 在继承情况下,派生类的作用域嵌套在基类作用域中:如果不能在派生类作用域中确定名字,就在外围基类作用域中查找该名字的定义. 正是这种类作用域的层次嵌套使我们能够直接访问基类的成员,就好像这些成员是派生类成员一样: Bulk_item bulk; cout << bulk.book() << endl; 名字book的使用将这样确定[先派生->后基类]: 1)bulk是Bulk_item类对象,在Bulk_item类中查找,找不到名