c++学习笔记-数据的共享与保护

558 阅读3分钟

1、标识符的作用域与可见性

1.1、标识符的作用域与可见性

  • 作用域是一个标识符在程序正文中有效的区域。
  • 作用域分类:
    • 函数原型作用域
    • 局部作用域(块作用域)
    • 类作用域
    • 文件作用域
    • 命名空间作用域

1.2、函数原形作用域

  • 函数原型中的参数,其作用域始于"(",结束于")"。

1.3、局部作用域

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

1.4、类作用域

  • 类的成员具有类作用域,其范围包括类体和非内联成员函数的函数体。
  • 如果在类作用域以外访问类的成员,要通过类名(访问静态成员),或者该类的对象名、对象引用、对象指针(访问非静态成员)。
  • 文件作用域
  • 不在前述各个作用域中出现的声明,就具有文件作用域,这样声明的标识符其作用域开始于声明点,结束于文件尾。

2、对象的生存期

2.1、静态生存期

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

2.2、动态生存期

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

3、类和静态成员

3.1、静态数据成员

  • 必须在类外定义和初始化,用(::)来指明所属的类。

4、类的友元

4.1、类的友元

友元是C++提供的一种破坏数据封装和数据隐藏的机制。 通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息。可以使用友元函数和友元类。

注:为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元。

4.2、友元函数

友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象名访问 private 和 protected成员

作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择。访问对象中的成员必须通过对象名。

例5-6 使用友元函数计算两点间的距离

#include <iostream>
#include <cmath>
using namespace std;
class Point { //Point类声明
  public: //外部接口
    Point(int x=0, int y=0) : x(x), y(y) { }
      int getX() { return x; }
      int getY() { return y; }
      friend float dist(Point &a, Point &b);
  private: //私有数据成员
      int x, y;
};
float dist( Point& a, Point& b) {
  double x = a.x - b.x;
  double y = a.y - b.y;
  return static_cast<float>(sqrt(x * x + y * y));
}
int main() {
  Point p1(1, 1), p2(4, 5);
  cout <<"The distance is: ";
  cout << dist(p1, p2) << endl;
  return 0;
}

4.3、友元类

若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员。

声明语法:将友元类名在另一个类中使用friend修饰说明。

class A {
    friend class B;

public:
    void display() {
        cout << x << endl;
    }

private:
    int x;
};

class B {
public:
    void set(int i);

    void display();

private:
    A a;
};

void B::set(int i) {
    a.x = i;
}

void B::display() {
    a.display();
};

4.4、类的友元关系是单向的

如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据。

5、多文件结构和预编译命令

5.1、c++程序的一般组织结构

  • 一个工程可以分为多个源文件:
    • 类声明文件(.h文件)
    • 类实现文件(.cpp文件)
    • 类的使用文件(main方法所在的.cpp文件)
  • 利用工程来组合各个文件
//文件1,类的定义,Point.h
class Point { //类的定义
public:          //外部接口
       Point(int x = 0, int y = 0) : x(x), y(y) { count++; }
       Point(const Point &p);
       ~Point() { count--; }
       int getX() const { return x; }
       int getY() const { return y; }
       static void showCount();          //静态函数成员
private:         //私有数据成员
       int x, y;
       static int count; //静态数据成员
};
 
//文件2,类的实现,Point.cpp
#include "Point.h"
#include <iostream>
using namespace std;
 
int Point::count = 0;            //使用类名初始化静态数据成员
 
Point::Point(const Point &p) : x(p.x), y(p.y) {
       count++;
}
 
void Point::showCount() {
       cout << "  Object count = " << count << endl;
}
 
//文件3,主函数,5_10.cpp
#include "Point.h"
#include <iostream>
using namespace std;
 
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;
}
例 5-10 多文件的工程

22.png

5.2、外部变量

批注 2020-03-04 160633.png

批注 2020-03-04 160702.png

条件编译指令——#if 和 #endif

#if  常量表达式
 //当“ 常量表达式”非零时编译
     程序正文 
#endif
......
条件编译指令——#else

  #if   常量表达式
     //当“ 常量表达式”非零时编译
       程序正文1
#else
  //当“ 常量表达式”为零时编译
       程序正文2
#endif
条件编译指令——#elif

#if 常量表达式1
    程序正文1  //当“ 常量表达式1”非零时编译
#elif 常量表达式2
    程序正文2  //当“ 常量表达式2”非零时编译
#else
    程序正文3  //其他情况下编译
#endif
条件编译指令

#ifdef 标识符
    程序段1
#else
    程序段2
#endif

批注 2020-03-04 160902.png