c++基础(六)

标识符的作用域与可见性

  • 作用域是一个标识符在程序正文中有效的区域。
  • 作用域分类
  1. 函数原型作用域
  2. 局部作用域(块作用域)
  3. 类作用域
  4. 文件作用域
  5. 命名空间作用域(详见第10章)

函数原形作用域

  • 函数原型中的参数,其作用域始于"(",结束于")"。
  • 函数原形作用域举例:double area(double radius);

局部作用域

  • 函数的形参、在块中声明的标识符;
  • 其作用域自声明处起,限于块中。
  • 局部作用域举例

void fun(int a) {

   int b = a;

   cin >> b;

   if (b > 0) {

     int c;

 

     ......

   }

}

类作用域

  • 类的成员具有类作用域,其范围包括类体和非内联成员函数的函数体。
  • 如果在类作用域以外访问类的成员,要通过类名(访问静态成员),或者该类的对象名、对象引用、对象指针(访问非静态成员)。

文件作用域

  • 不在前述各个作用域中出现的声明,就具有文件作用域,这样声明的标识符其作用域开始于声明点,结束于文件尾。

可见性

  • 可见性是从对标识符的引用的角度来谈的概念
  • 可见性表示从内层作用域向外层作用域“看”时能看见什么。
  • 如果标识在某处可见,就可以在该处引用此标识符。
  • 如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可见。
  • 对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见。

对象的生存期

静态生存期

  • 这种生存期与程序的运行期相同。
  • 在文件作用域中声明的对象具有这种生存期。
  • 在函数内部声明静态生存期对象,要冠以关键字static 。

动态生存期

  • 块作用域中声明的,没有用static修饰的对象是动态生存期的对象(习惯称局部生存期对象)。
  • 开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。

类的静态数据成员

  • 用关键字static声明
  • 为该类的所有对象共享,静态数据成员具有静态生存期。
  • 必须在类外定义和初始化,用(::)来指明所属的类

 案例:

#include <iostream>
using namespace std;
class Point {     //Point类定义
public:       //外部接口
    Point(int x = 0, int y = 0) : x(x), y(y) { //构造函数
        //在构造函数中对count累加,所有对象共同维护同一个count
        count++;
    }
    Point(Point &p) {    //复制构造函数
        x = p.x;
        y = p.y;
        count++;
    }
    ~Point() { count--; }
    int getX() { return x; }
    int getY() { return y; }
    void showCount() {           //输出静态数据成员
        cout << "  Object count = " << count << endl;
    }
private:      //私有数据成员
    int x, y;
    static int count;       //静态数据成员声明,用于记录点的个数
};
int Point::count = 0;//静态数据成员定义和初始化,使用类名限定
int main() {       //主函数
    Point a(4, 5);     //定义对象a,其构造函数回使count增1
    cout << "Point A: " << a.getX() << ", " << a.getY();
    a.showCount(); //输出对象个数
    Point b(a); //定义对象b,其构造函数回使count增1
    cout << "Point B: " << b.getX() << ", " << b.getY();
    b.showCount();       //输出对象个数
    return 0;
}

上面案例中,我们需要记录下point类的对象的数目,我们不可能将这个变量存放于类的私有成员中,因为这样只能通过对象取访问,并且每声明一个类的对象,这个数目就要增加1。因此,我们可以将其定义为类的静态成员变量,这个变量是为所有的类对象共有的。但是,这样也会存在一个问题:当没有定义类的对象时,我们能不能知道类对象的个数呢?如果要通过类的对象来访问这个变量的话,那么需要先声明一个对象,但是类的对象还没有被声明,如何解决这个问题呢?这就需要用到类的静态函数成员了。

类的静态函数成员

  • 类外代码可以使用类名和作用域操作符来调用静态成员函数。
  • 静态成员函数主要用于处理该类的静态数据成员(为什么?),可以直接调用静态成员函数。
  • 如果访问非静态成员,要通过对象来访问。

将上面的程序稍作修改,如下:

#include <iostream>
using namespace std;
class Point {
public:
    Point(int x = 0, int y = 0) : x(x), y(y) { count++; }//构造函数
    Point(Point &p) {    //复制构造函数
        x = p.x;
        y = p.y;
        count++;
    }
    ~Point() { count--; }
    int getX() { return x; }
    int getY() { return y; }
    static void showCount() {
        cout << "  Object count = " << count << endl;
    }
private:
    int x, y;
    static int count;       //静态数据成员声明,用于记录点的个数
};
int Point::count = 0;//静态数据成员定义和初始化,使用类名限定
int main() {
    Point a(4, 5);     //定义对象a,其构造函数回使count增1
    cout << "Point A: " << a.getX() << ", " << a.getY();
    Point::showCount();       //输出对象个数
    Point b(a); //定义对象b,其构造函数回使count增1
    cout << "Point B: " << b.getX() << ", " << b.getY();
    Point::showCount();       //输出对象个数
    return 0;
}

我们在函数中增加了一个静态成员函数:showcount(),那么在访问类的静态成员变量时就可以不通过对象来访问,而是通过这个静态成员函数来访问,即使没有声明类的对象。但是静态成员函数不能直接访问对象的数据成员,而是要将对象传递给静态函数才可以访问。

类的友元

  • 友元是C++提供的一种破坏数据封装和数据隐藏的机制。
  • 通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息。
  • 可以使用友元函数和友元类。
  • 为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元。

友元函数

  • 友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象名访问 private 和protected成员
  • 作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择。
  • 访问对象中的成员必须通过对象名,也就是必须将类的对象作为参数传递给函数,一般我们选择引用传递,因为这样程序的开销会更小,但是引用时数据是双向传递的,因此可以在传参数时设定为常引用,这样就不会允许函数对传递进来的参数做修改了,保证了数据的安全性。

友元类

  • 若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员。
  • 声明语法:将友元类名在另一个类中使用friend修饰说明。
  • 类的友元关系是单向的:如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据。

 

猜你喜欢

转载自www.cnblogs.com/puheng/p/9296925.html
今日推荐