5_数据的共享与保护
数据的共享与保护
标志符的作用域和可见性
作用域
- 函数原型作用域:函数形参表括号
- 局部作用域(块作用域):函数体或大括号,函数的形参
- 类作用域:类体和成员函数体
- 文件作用域:开始于声明点,结束于文件尾
- 命名空间作用域
#include <iostream>
using namespace std;
int i = 0; //全局变量,文件作用域
int main(){
i= 5;
{
int i; //局部变量,局部作用域
i = 7;
cout << i << endl;
}
cout << i << endl;
return 0;
}
对象的生存周期
- 静态生存期:整个程序运行期间都存在,static修饰,未初始化默认为0
- 动态生存期:结束于作用域尾
#include <iostream>
using namespace std;
int i = 0; //全局变量,文件作用域
void other(){
static int a = 1; //静态局部变量
int c = 10; //局部变量,动态生存期
a += 2;
i +=32;
c +=5;
cout << "i: " << i << " a: " << a << " c: " << c << endl;
}
int main(){
other();
other();
return 0;
}
类的静态成员
类的静态数据成员
- static修饰,为该类的所有对象共享,具有静态生存期
- 必须在类外定义和初始化,用 :: 来指明所属的类
类的静态函数成员
- 一般只用于处理类的静态数据成员,不处理具体某个对象的数据。
#include <iostream>
using namespace std;
class Point{
public:
Point(int x=0, int y=0):x(x), y(y){
count++;
}
Point(const 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::showCount(); //可以直接调用,不需要通过对象调用
Point a(4, 5);
cout << a.getX() << a.getY() << endl;
a.showCount(); //也可以通过对象调用
Point b(a);
cout << b.getX() << b.getY() << endl;
Point::showCount();
return 0;
}
友元
- 友元模块可以访问到另一个模块中被隐藏的信息
- 关键字 friend 修饰,可以访问private 和 protected成员
- 在封装和快速性达到平衡
友元函数
#include <iostream>
#include <cmath>
using namespace std;
class Point{
public:
Point(int x=0, int y=0):x(x), y(y){
}
int getX(){return x;}
int getY(){return y;}
friend double dist(const Point& a, const Point& b){ //友元函数
double x = a.x - b.x;
double y = a.y - b.y;
return static_cast<float>(sqrt(x*x+y*y));
}
private:
int x, y;
};
int main(){
Point p1(1, 5), p2(1,2);
cout << dist(p1, p2) << endl;
return 0;
}
友元类
- 若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员
- 友元关系是单向的
共享数据的保护
- 关键字 const 修饰
常对象
const Point a(3, 4); //a是常对象,不能被更新
常成员函数
-
返回类型 函数名(参数表) const
-
不更新对象的数据成员
-
通过常对象只能调用它的常成员函数,非常对象也可以调用它的常成员函数
-
可以用来区分重载函数
#include <iostream>
#include <cmath>
using namespace std;
class Point{
public:
Point(int x=0, int y=0):x(x), y(y){
}
int getX(){return x;}
int getY(){return y;}
void print();
void print() const; //常成员函数
private:
int x, y;
};
void Point::print(){
cout << x << y << endl;
}
void Point::print() const{
cout << x << y << endl;
}
int main(){
Point p1(1, 5);
p1.print(); //调用void print()
const Point p2(2, 4);
p2.print(); //调用void print() const
return 0;
}
常数据成员
- 只能在初始化的时候赋值,其他时候不可以改变其值
#include <iostream>
#include <cmath>
using namespace std;
class A{
public:
A(int i);
void print();
private:
const int a; // 常数据成员的声明
static const int b; //静态常数据成员的声明
};
const int A::b = 10; // 静态常数据成员初始化
A::A(int i):a(i){} //常数据成员通过列表初始化,不能通过函数体初始化
void A::print(){
cout << a << b << endl;
}
int main(){
A a1(100), a2(0);
a1.print();
a2.print();
return 0;
}
常引用
- 不能通过常引用修改原来的值
- 非常安全
多文件结构与预编译命令
多文件结构
- 类声明文件(.h文件)
- 类实现文件(.cpp文件)
- 类的使用文件(main所在的.cpp文件)
编译与链接
//类的定义
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; //静态数据成员声明
};
//类的实现
#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;
}
//主函数文件
#include <iostream>
#include "point.h"
using namespace std;
int main(){
Point a(4, 5);
cout << a.getX() << a.getY() << endl;
Point::showCount();
Point b(a);
cout << b.getX() << b.getY() << endl;
b.showCount();
return 0;
}
外部变量与函数
-
外部变量:文件作用域中定义的变量,默认情况下为外部变量;若需在其他文件中使用,则使用extern关键字修饰
-
外部函数:类定义之外的函数具有文件作用域,若需在其他文件使用只需extern声明一下即可
-
在匿名空间中定义的变量和函数不会暴露给其他单元
namespace { int n; void f(){ n++; } }
编译预处理命令
-
include:将一个源文件插入到当前源文件中该点处
- 自定义的.h文件在include时用 " ",会现在当前工作目录找,然后再到系统目录找;而系统.h文件使用 < >,直接到系统目录找
-
define:宏定义指令
- 定义符号常量,可以用const取代
- 定义带参数宏,可以用内联函数取代
-
undef:删除#define定义的宏
-
if 和 #endif:选择编译
#if 常量表达式 程序正文1 //当常量表达式非零时编译 #else 程序正文2 #endif
-
ifdef 和ifndef:选择编译,一般在头文件中使用;避免多次编译
#ifdef 标志符 程序段1 //当标识符未被定义过则编译 #else 程序段2 #endif#