C++类定义中名字的查找规则

1.在了解类定义中,名字的查找规则之前,我们先来了解下普通的名字查找规则

  • 当前作用域中查找,只考虑在名字使用之前出现的声明
  • 外层作用域中查找
  • 没找到,报错

代码示例:

void PrintValue(){
    printf("%d\n",a);	// 这里会报错,因为a的定义出现在函数的后面
}
int a = 100;
int main( void ){
    PrintValue();
    return 0;
}

int a = 100;
void PrintValue(){
    printf("%d\n",a);	// 这里不会报错
}
int main( void ){
    PrintValue();
    return 0;
}

2.类中使用的名字查找规则

2.1首先我们需要先了解编译器对类定义的处理逻辑:

  • 首先,编译成员的声明(这一步中名字的查找规则和上面讲的普通的名字查找规则一样)
  • 直到类全部可见后,才会编译函数体

类中的所有声明包括:类型名(使用typedef,using声明定义的类型名),成员函数的返回类型和形参列表中的类型名,数据成员的类型名

这里举个例子让大家有一个直观的感受

class CD{
public:
	...
	int GetValue() const{ 
		return a;		// 如果这里还使用普通的名字查找规则,那么会先处理函数体中的变量a,此时变量a还没有出现
	}
private:
	int a = 100;
};

上述代码编译的时候没有报错,说明在编译过程中,GetValue函数,找到了在它下面定义的成员变量a。

2.2类定义中的 类型名要特殊处理

一般来说,内层作用域可以重新定义外层作用域中的名字,即使该名字已经在内层作用域中使用过。

#include <iostream>
using namespace std;

typedef doubel Money;

int main( void ){
    Money a;            // a是doubel类型
    typedef int Money;    
    Money b;            // b是int类型
    return 0;
}

上述代码编译成功。

但是在类中,如果成员使用了外层作用域中的某个名字,而该名字代表一种类型,则类不能在之后从新定义该名字。

实例代码:

typedef double Money;
class Account{
public:
    Money balance(){
        return bal;
    }

private:
    using Money = double;
    // typedef int Money;
    Money bal;
};

上面的代码在编译的时候会报错!!!

为什么会报错呐?如果不报错,由于编译器对类的定义分2步处理,成员函数balance的返回类型Money是外层作用域中定义的double类型,而成员函数balance函数体中的返回值bal的类型,是类内部定义double类型,假如我们将类内部定义的Money类型设置为int,此时成员函数balance的返回类型就不一致了。

类型名的定义通常出现在类的开始处,这样就能确保,所有使用该类型的成员,都出现在类型名的定义中。

下面是类型名正确的用法:

typedef double Money;
class Account{
public:
    using Money = double;
    // typedef double Money;
    Money balance(){
        return bal;
    }

private:
    Money bal;
};

2.3成员函数中名字的查找规则(函数体中使用的名字)

这里还分为两种情况

2.3.1成员函数定义在类的内部(内联的成员函数)

  • 函数体内部,名字使用之前的范围内查找
  • 如果没有在函数体中找到,在类内继续查找,此时类的所有成员都可以被考虑
  • 如果在类中也没找到,在类定义之前的外层作用域中查找
  • 没有找到,报错

2.3.2成员函数定义在类的外部

  • 函数体内部,名字使用之前的范围内查找
  • 如果没有在函数体中找到,在类内继续查找,此时类的所有成员都可以被考虑
  • 如果在类中也没找到,则在成员函数定义之前的作用域中查找(这里也包含了类定义之前的作用域了)
  • 没有找到,报错
class Screen{
public:
    typedef std::string::size_type pos;
    void setHeight( pos );
    pos height = 0;
};

Screen::pos verify( Screen::pos );

void Screen::setHeight( pos var ){
    height = verify( var );
}

上述代码中:全局函数verify的声明在Screen类的定义之前是不可见的。然而,对于定义在类外部的成员函数来说,可以在成员函数定义之前的作用域中查找!!!所以这里依然可以找到。

总结:在类中的名字查找,主要是成员函数函数体中名字的查找,根据成员函数的定义位置,名字的查找规则稍微有点区别。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值