C++中类的作用域

一:在类外部定义成员函数

        当我们在类外部定义成员函数时,一旦遇到类名,定义的剩余部分(即参数列表与函数体)就在类的作用于之内了;相反,在遇到函数名之前的部分(返回值)位于类的作用于之外。

#include <vector>

class StudentManager;
class Student;

class Student{
private:
    friend class StudentManager;
};

class StudentManager{
public:
    using StudentId = std::vector<Student>::size_type; // 每个学生的编号
    void clear(StudentId);
    StudentId append(const Student);
private:
    std::vector<Student> students;
};

void StudentManager::clear(StudentId i) {
    students.erase(students.begin()+i);
}

StudentManager::StudentId StudentManager::append(const Student s) {
    students.push_back(s);
}

        我们定义了一个Student类,并用StudentManager来管理Student类。我们在StudentManager类外部定义了StudentMnager类的两个成员函数clear与append,用于清除指定位置的元素与添加新的Student成员,StudentId为StudentManager类的成员变量。

        在定义clear函数时,由于函数的返回类型不属于StudentManager类,所以未加作用域运算符,在遇到函数名后使用作用域运算符进入StudentManager作用域,而后的参数列表与函数体默认是位于StudentManager类中的,所以没有出现作用域运算符。

        但在定义append函数时,由于函数的返回类型是StudentManager类的成员且未遇到函数名,则该处位于StudentManager作用域外,需显式添加作用域运算符来使用类中成员。

二:类中的名字查找

        对于定义在类中的成员函数来说,解析其中名字时首先编译成员的声明,等到类全部可见后再编译函数体。

1.用于类成员声明的名字查找

        声明中使用的名字,包括返回类型与参数列表中使用的名字,必须在使用前可见。如果某个名字在类中未出现,则会继续在定义该类的作用域中继续查找。

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

        当编译器看到balance函数声明语句时 ,它将在Account类的范围内寻找对Money的声明。编译器只会考虑出现balance函数前出现的声明(因为未到编译函数体阶段)由于在类内未找到,则在定义Account类的作用域内查找,发现其为double类型的别名,则double被用于balance函数的返回类型。

        其次,balance函数体在整个类全部可见后被处理,因此该return语句返回的是类中定义的Money类型的bal,而非函数体之外的int类型的bal。

2.类型名的特殊处理

        一般来说,内层作用域可以重新定义外层作用域中的名字,即使改名字已经在内层作用域中使用过。然而在类中,如果成员使用了外层作用域中的某个名字,且恰好该名字代表一种类型,则类不能在之后重新定义该名字。

typedef double Money;
class Account{
public:
    Money balance(){
        return bal;
    }
private:
    typedef double Money; // error!不能重新定义Money
    Money bal;
};

        即使重定义的Money类型与外层作用域中的类型一致,该代码依然是错误的。

        编译器不负责检查此类错误!

 3.成员函数定义中的名字查找

        成员函数中使用的名字解析方法:首先只考虑在成员函数中出现的声明;如果未找到则继续在类内查找,此时类中的所有成员均可考虑;最后在类定义之前的作用域中查找。

int a = 2;
class Class{
public:
    int get(int b){
        return a * b * c;
    }
private:
    int b = 3;
    int c = 4;
};

        编译器在get函数中遇到了 a,b,c名字。首先在函数作用域内查找相关名字,在参数列表中找到了b,则函数体中的b为参数列表中的b;在函数作用域内未找到a与c,进一步在类中查找,找到了名字c,则函数体中的c为类中定义的c = 4;a未在类中找到,进一步在类定义的作用域中找到了a = 2,则函数体中的a为2。如果我们调用该函数并将b赋值为5,则其返回值为40。

        当然我们可以使用作用域运算符来将b赋值为类中private部分定义的b=3,此时无论参数b为何值,其返回值都为24。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QiNwWa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值