C++——数据共享与保护

本文深入探讨了C++编程中的核心概念,包括作用域与可见性、对象的生存期、类的友元、共享数据的保护等。通过具体示例,讲解了不同作用域下标识符的有效范围,静态与动态生存期的区别,以及如何通过友元函数和类来访问私有成员。同时,介绍了如何使用const修饰符来保护共享数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

1.1作用域

作用域是一个标识符在程序正文中有效的区域

分类

1、函数原形作用域
函数原型中的参数,其作用域始于 " ( ",止于" ) ",限与小括号内
2、局部作用域(块作用域)
函数的形参、在块中声明的标识符的作用域;自声明处起,限于块中

void fun(int a) {    //a的范围在整个函数
    int b = a;    //b的范围仅限fun函数体
    cin >> b;
    if (b > 0) {
        int c;    //c的范围仅限if语句
        ......
    }
}

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

1.2可见性

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

二、对象的生存期

2.1静态生存期

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

2.2动态生存期

始于声明处,止于命名该标识符的作用域结束处
块作用域中声明的,没有用 static 修饰的对象是动态生存期的对象(习惯称局部生存期对象)

三、类的友元

友元是 C++ 提供的一种破坏数据封装和数据隐藏的机制
类的友元关系是单向的。如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有和保护数据
为确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元

3.1友元函数

友元函数是在类声明中由关键字 friend 修饰说明的非成员函数,在其函数体中能够通过对象名访问 private 和 protected 成员
作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择
访问对象中的成员必须通过对象名

//1.2例
#include<iostream>
using namespace std;
 
int i;  //全局变量,文件作用域
int main() {
    i = 5;  //为全局变量i赋值
    {
        int i;  //局部变量,局部作用域
        i = 7;
        cout << "i = " << i << endl;    //输出7
    }
    cout << "i = " << i << endl;    //输出5
    return 0;
}

结果:
i = 7
i = 5 



//2.2例
#include<iostream>
using namespace std;

int i = 1; // i 为全局变量,具有静态生存期
void other() {
    static int a = 2;
    static int b;   //a,b为静态局部变量,具有全局寿命,局部可见, 只在第一次进入函数时被初始化
    int c = 10;     //c为局部变量,具有动态生存期,每次进入函数时都初始化
 
    a += 2; i += 32; c += 5;
    cout << "---OTHER---\n";
    cout << " i: " << i << " a: " << a << " b: " << b << " c: " << c << endl;
    b = a;
}
 
int main() {
    static int a;   //静态局部变量,有全局寿命,局部可见
    int b = -10;    //b, c为局部变量,具有动态生存期
    int c = 0;
 
    cout << "---MAIN---\n";
    cout << " i: " << i << " a: " << a << " b: " << b << " c: " << c << endl;
    c += 8; other();
 
    cout << "---MAIN---\n";
    cout << " i: " << i << " a: " << a << " b: " << b << " c: " << c << endl;
    i += 10; other();
    return 0;
}
 
结果:
---MAIN---
 i: 1 a: 0 b: -10 c: 0
---OTHER---
 i: 33 a: 4 b: 0 c: 15
---MAIN---
 i: 33 a: 0 b: -10 c: 8
---OTHER---
 i: 75 a: 6 b: 4 c: 15 



//3.1例
//此例亦为常引用举例
 
#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 float dist(Point &a, Point &b);
private:
    int x, y;
};
 
float dist(const Point& a, const Point& b) {    //将引用设置为常引用不会意外地发生对实参的更改
    double x = a.x - b.x;
    double y = a.y - b.y;
    return (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;
}
 
结果:
The distance is: 5

3.2友元类

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

```c++
class A {
friend class B; //类B是类A的友元(关键)
public:
void display() {
cout << x << endl;
}
private:
int x;
};

class B {
public:
void set(int i);
void display();
private:
A a; //类B可以访问类A的任意成员
};

//接口与实现分离
void B::set(int i) {
a.x = i;
}
void B::display() {
a.display();
};
``` 

四、共享数据的保护

对于既需要共享、又需要防止改变的数据应该声明为常类型(用 const 进行修饰)

4.1常对象

必须进行初始化, 且不能被更新
语法形式const 类名 对象名

class A {
public:
    A(int i, int j) { x = i; y = j; }
private:
    int x, y;
};
const A a(3, 4);    //a是常对象,不能被更新

4.2常成员

4.2.1常数据成员

语法形式const 数据类型 变量名
不为常数据成员提供成员初始化值是编译错误;成员初始化值是成员初始化列表的一部分,由数据成员名和其后包含该成员初始值的括号组成
常数据成员和引用数据成员必须通过成员初始化列表初始化;成员初始化列表在构造函数的形参列表和大括号之间;成员初始化列表在函数体之前执行

4.2.2常成员函数

语法形式返回值类型 函数名(参数表)const { 函数体 }
关键字const在函数原型和函数定义中都要说明,即在函数原型和函数定义的形参列表后加关键字 const
常对象只能调用常成员函数,且不改变对象的数据成员
将构造函数和析构函数声明为 const 是编译错误

#include<iostream>
using namespace std;
 
class A {
public:
    A(int i) : a(i) { }
    void printA();
private:
    const int a;
    static const int b;     //静态常数据成员
};
class R {
public:
    R(int r1, int r2) : x(r1), y(r2) { }
    void print();
    void print() const;    //const也是区分重载函数的一个因素
private:
    int x, y;
};
 
const int A::b = 10;
void A::printA() {
    cout << a << ":" << b << endl;
}
void R::print() {
    cout << x << ":" << y << endl;
}
void R::print() const {    //显式的标出const,编译器才会认真审查函数是否改变对象状态 
    cout << x << ":" << y << endl;
}
 
int main() {
    //常数据成员 
    A c(16);
    c.printA();
    cout << endl;
    //常成员函数 
    R a(5, 4);
    a.print();    //调用void print();若没有定义该函数,对象a调用常函数。普通对象可以调用常函数 
    const R b(20, 52);    //定义的常对象只能用常函数处理;不是常函数,不能通过常对象调用 
    b.print();    //调用void print() const
    return 0;
}
 
结果:
16:10
 
5:4
20:52 

4.3常引用

被引用的对象不能被更新
语法形式const 类型说明符 &引用名
举例:见友元函数举例

4.4常数组

数组元素不能被更新
语法形式类型说明符 const 数组名[大小]

4.5常指针

指向常量的指针

转载于:https://www.cnblogs.com/xxwang1018/p/11546669.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值