【C++】类(下):类成员与explicit、const、mutable、volatile、static、friend关键字

【C++】类(下):类成员与explicit、const、mutable、volatile、static、friend关键字,第1张

C++类与对象知识点合集:

【C++】类(上):初识类和对象
【C++】类(中):类中的默认成员函数
【C++】类(下):类成员与explicit、const、mutable、volatile、static、friend关键字


目录
  • 关键字explicit
  • 关键字const
    • const修饰变量
    • const修饰指针变量
    • const修饰引用变量
    • const修饰类外函数
    • const修饰类成员
      • 1. 修饰类的实例对象
      • 2. 修饰类的成员变量
      • 3.修饰类的成员函数
  • 关键字mutable
  • 关键字volatile
  • 关键字static
  • 关键字friend
    • 友元函数
    • 友元类


关键字explicit

explicit:用来声明类的单参构造函数为显示调用,使其不能隐式转换。

  • 作用:消除单参构造函数(或有缺省参数的全参构造函数)的类型转换问题;
  • implicit关键字作用和explicit相反,声明构造函数为隐式调用;
  • 无参构造函数和多参构造函数默认为显示调用的,单参构造函数默认为隐式调用;
  • 隐式调用的构造函数会导致:函数参数会发生类型隐式转换;
关键字const

const:用来修饰一个变量或对象,约束其值不能被修改。

const修饰变量
  • 该变量被标记为常量,无法被修改;
  • const修饰的变量必须被初始化;
const修饰指针变量
  • const 在 * 前,表示常量指针:指向常量的指针
    const int* p;
    int const* p;
  • const 在 * 后,表示指针常量:该指针不能指向其他变量
    int* const p;
const修饰引用变量
  • 引用变量被标记为常量引用,常量引用不能直接修改被引用的变量;

  • const修饰的引用变量可引用非const类型变量(属于权限缩小,合理):

  • const修饰的引用类型与所引用对象类型不一致:

const修饰类外函数
  • 不能直接对函数+const修饰;

  • const修饰函数的参数,表示该参数在函数体内不能修改;

  • const修饰参数的函数不会与普通参数的函数构成重载;

  • const修饰函数返回值;

const修饰类成员 1. 修饰类的实例对象
  • 表示该对象是一个常量,不能改变内容;
  • 被const修饰的类对象,既不能改变类中的成员变量,也不能调用类中任何非const成员函数;
2. 修饰类的成员变量
  • const修饰的成员变量不能被修改;
  • 只能在初始化列表中被初始化(引用变量也是);
3.修饰类的成员函数
  • const直接修饰成员函数表示此函数不能对任何成员变量进行修改;
    本质:修饰的是该成员函数隐含的this指针

  • 静态成员函数不能使用const修饰(没有this指针);

  • 为了提高程序安全性,如果成员函数内部不会进行修改元素的 *** 作,那么将该成员函数直接定义为const函数(例如打印函数);

  • 四种常见情景:

  • const也可以指修饰成员函数的参数、返回值;

关键字mutable

mutable:为了突破const的限制而设置,被mutable修饰的变量,将永远处于可变的状态。

  • 可以用在一个const函数中,甚至结构体变量或者类对象为const,其mutable成员也可以被修改
关键字volatile

volatile:称为最易变的关键字,其修饰的数据,编译器不可对其进行执行期寄存于寄存器的优化。


一个被const修饰的变量其实并没有直接存储到了静态常量区,只是告诉编译器该变量以标记为常量,不可修改,但其实通过变量指针解引用依旧可以修改该const常量值

而如果对于一个静态区的变量使用const关键字修饰,就无法通过指针修改其值:


现在来看这段特殊的代码:

#include <windows.h>  //使用Sleep函数

int main()
{
	const int a = 1;
	int* pa = (int*)&a;
	int cur = 0;
	while (a)
	{
		if (cur == 5)
		{
			*pa = 0;
		}
		cur++;
		cout << a << endl;
		Sleep(1);
	}

	return 0;
}

这个代码非常易懂,就是让循环进行5次后,通过指针修改const循环条件变量的值让循环结束,结果应该是循环执行5次:

之所以会出现上面的情况,"罪魁祸首"就是 *** 作系统;

而如果为了上面的const变量加上关键字volatile,就是告诉OS不要进行优化,而是生成对应代码直接存取原始内存地址,即使是const修饰的变量,这就是最易变关键字volatile的作用;

这个关键字现实中的使用场景常见于多线程编程中,满足多线程同步、中断、硬件编程等特殊需要,因为一个共享变量可能在当前线程好像是不可修改的,但在其他线程有可能会修改这个值,有了关键字volatile就可以避免这种bug;

关键字static

此关键字知识点详见博客:【C++】详谈关键字static

【几点注意事项】:

  • static修饰的类成员变量——静态成员变量;
  • static修饰的类成员函数——静态成员函数;
  • 静态成员属于类而不属于任何对象(因此对象大小不包括);
  • 静态成员属于类成员,仍受访问限定符(public、protected、private)的限制;
  • 静态成员函数只可以访问静态成员变量(普通函数均可以);
  • 静态成员函数不能调用普通成员函数,但可以被其他普通函数调用;静态成员函数只可以调用静态成员函数;
  • 静态成员函数无法修饰为const函数(不允许也没意义);
关键字friend

为了提高编程的灵活性和效率,C++提供了friend关键字来实现类的友元函数和友元类。

友元函数

一个类的成员变量如果被设为private私有权限,那么类外的函数是无法对改成员变量进行访问的(类内成员函数访问类成员不是权限限制);

友元函数,可以实现非类成员函数,但可以访问类的私有成员变量

  • 友元函数定义在类外,在类内只能声明它的函数原型,并加上friend关键字;
  • 友元函数不是成员函数,它是类的朋友;
  • 友元函数是类外函数,没有this指针;
  • 友元函数可以访问类的全部成员;
  • 友元关系是单向的,不具有交换性;
// 测试类
class Test
{
	// 声明友元函数
	friend void Print(const Test& A);
private:
	int _a;
};
// 定义友元函数,无需加friend关键字
void Print(const Test& A)
{
	cout << A._a << endl;
}
友元类

在一个类A使用关键字friend声明类B,那么类B就是类A的友元类。那么类B的成员函数可以访问类A的所有成员;

  • 声明位置:公有私有均可,常写为私有(把类看成一个变量);

  • 声明: friend + class + 类名(不是对象);

  • 类名必须是程序中的一个已定义过的类;

  • 友元关系是不能被继承的,就像父亲的朋友未必是儿子的朋友;

  • 友元关系是单向的,不具有交换性;

    若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明;

  • 友元关系不具有传递性;

    若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的声明;

class A
{
private:
	int _a;
	friend class B;  // 声明类B为类A的友元类
};

class B  
{
public:
	void Fun(A& a)  //类B可以访问类A的任何成员
	{
		cout << a._a << endl;
	}
};

类和对象
完结撒花 ~

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/788925.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-05
下一篇 2022-05-05

发表评论

登录后才能评论

评论列表(0条)

保存