IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Cukor丘克说CPP进阶01 2021-08-12 -> 正文阅读

[C++知识库]Cukor丘克说CPP进阶01 2021-08-12

C++数据的共享和保护

对象生命周期

静态生命周期

定义:**如果对象的生命周期于程序的运行期相同,那么它就是具有静态生命周期。**在文件作用域中声明的对象都具有静态生命周期。(通俗点,就是全局变量是是静态的,直到程序运行结束才死亡),如果在函数中的局部作用域中声明具有静态生命周期的对象,则要加上关键字static。(通俗点,加了staitic的变量是静态变量,直到程序运行结束才死亡)。这个在C语言中也有过这样的定义。在C++中仍然沿用这样的定义方式。

上代码:

#include<iostream>
using namespace std;
//静态变量只初始化一次
void Fun()
{
	static int k = 9;
	cout << k++ << endl;
}
class MM
{
public:
	//这里使用了友元和运算符重载
	friend ostream& operator<<(ostream& out, MM mm);
protected:
	string name;
	int age;
};

MM mm;
int i;	//在文件作用域,属于全局变量(对象),没有初始化,默认初始化为零

int main()
{
	cout << i << endl;
	static int j = 3;	//定义了一个静态的整型变量j并且初始化为3
	cout << j << endl;
	Fun();				//打印9
	cout << mm << endl;
	//输出:		0
    //静态变量(对象)只初始化一次,如果没有初始化,这默认为零,根据类型自行进行隐式转换
	Fun();				//打印10
	return 0;
}

ostream& operator<<(ostream& out, MM mm)
{
	out << mm.name << '\t' << mm.age << endl;
	return out;
}

动态生命周期

非静态生命周期就是动态生命周期

在函数作用域中声明的变量就是动态的,在局部作用域中声明的变量具有动态生命周期,在声明处诞生,在声明所在的块指向完毕就死亡。动态声明的变量没有初始化其初值未定是一个垃圾值,即上次使用到这个内存的数据是多少就是多少,一般来说,数字的垃圾值是负数,字符的垃圾值是"烫烫烫"等中文样式。

上代码

#include<iostream>
using namespace std;

void testFun()
{
	int i = 9;//	定义了一个动态的整型变量i,初始为9
	//下一次进来的时候会在一次这样定义这个变量
	cout << i++ << endl;
}

void testFun2()
{
    int k;	//没有初始化,存放的是垃圾值,一般是负数
    cout<<k++<<endl;
}

int main()
{
	testFun();		//打印:9
	testFun();		//打印:9
	testFun();		//打印:9
	testFun2();		//垃圾值
    testFun2();		//垃圾值
    testFun2();		//垃圾值
	return 0;
}

类的静态成员

如果某个类的属性是整个类共有的,而不属于任何一个具体的对象,则用static关键字类声明为静态成员。

简单来说就是在类中的成员使用了静态性质,那么这个静态的成员就是属于整个类,而不是某一个类的对象独有的。而静态则用static 修饰。

**类的静态成员只能在类中声明在类外实现。包括属性和行为。**之所以要这样做,是因为要给静态成员单独分配一个空间,这个空间是整个类公有。

举个简单的例子:

在学生类中,有姓名和年龄等属性是单个对象特有的,不同的学生有不同的姓名,也要自己对应的年龄,当他们修改了自己的姓名并不影响到其他学生的姓名;修改年龄也是一样的,就像是你本来是20岁,然后你骗别人说你18岁,于是你自己改了自己的年龄,但对别人来说,比如的年龄还是别人原来的年龄。但是当学生类中有一个静态的成员就不一样了,这个静态成员是学生类共有的。就比如教室里的黑板,每个学生都有权力在这个黑板上写字,每写上一个新的东西就代表了这个黑板是改变的,每次都长得不一样嘛。所以当在黑板上写上“某某某喜欢某某某”的时候,在其他学生的眼中是可以看得到的。所以说静态成员就是这个意思。没有加static关键字的成员就是自己特有的,加了static关键字就是整个类共有的。

类的静态数据成员(类的静态属性)

静态的数据项(静态属性)属于整个类,不属于类的某个对象。类的数据成员必须是在类中声明,在类外初始化。访问可以不需要对象,但是需要类名限定,同时也是受类的权限限定。

#include<iostream>
using namespace std;

class Student
{
public:
    string name;	//学生姓名	单个学生类的对象自己有
    int Stuclass;	//学生班级	单个学生类的对象自己有
    static int blackboard;	//黑板	  全体学生类的对象共有
};
//静态成员必须要在类外初始化,而且必须用类名标识,并且不需要关键字static
int Student::blackboard = 4;

int main()
{
    Student Cukor;	//创建了一个学生类的对象
    Student Jack;	//又创建了一个学生类的对象
    cout << "Cukor:" << Cukor.blackboard << '\t' << "Jack:" << Jack.blackboard << endl;
    //同时访问这两个对象中的静态属性,结果都是一样的
    //下面的代码是通过其中的一个对象去修改这个静态属性的内容,然后再用这两个对象访问这个静态属性
    Cukor.blackboard = 99;
    cout << "Cukor:" << Cukor.blackboard << '\t' << "Jack:" << Jack.blackboard << endl;
    //结果法相两个对象的静态属性的内容都是一样的,也就是可以证明静态属性是类的所有的对象共有
    //再创建第三个学生类的对象,出来再去访问静态属性的时候也的得到一样的结果
    Student Tom;
    cout <<"Tom: "<<Tom.blackboard << endl;
    return 0;
}

静态函数成员(类的静态行为)

行为就是一个动作吧。那么在C++中就是用函数去实现。当使用了static关键字修饰的类的成员函数,那么这个函数就是整个类共有的函数。再继续用上面的例子,上面说了黑板是整个学生类共有的属性,那么这里就再加一个“擦黑板”的行为。我们想让学生去擦教室里黑板(原本的黑板上写了很多东西,现在让学生去擦)。那现在,Cukor这个同学上去把黑板擦了,Jack看到黑板已经被擦干净了,那Jack就没有必要再去擦黑板了吧。如果Cukor只是擦了自己的书桌,Cukor的书桌干净了,但对于Jack来说Jack的书桌还是杂乱无章的。那Cukor擦自己的书桌的行为就不影响到Jack,所以Jack也想要自己的桌面整洁,那就得自己动手。那么这个例子中呢,擦黑板就是静态的,是大家共有的;而擦桌子是动态的,是特有的。

静态函数成员的函数内部不能使用this指针,因为this指针是实例对象的地址,在对象没创建出来是抽象的(不存在的),而因为静态函数成员属于整个类,所以this指针不知道指的是哪个具体的对象。

#include<iostream>
using namespace std;
class Student
{
public:
    string name;	//学生姓名	单个学生类的对象自己有
    int Stuclass;	//学生班级	单个学生类的对象自己有
    //静态成员函数可以来类中实现
    static void ourBK()
    {
        blackboard *= -1;
        if (blackboard == 1)
        {
            cout << "黑板已经擦干净" << endl;
        }
        else
        {
            cout << "黑板上写了\"某某某我喜欢你\"" << endl;
        }
    }
    //静态成员函数可以在类中声明在类外实现
    static void print();
protected:
    static int blackboard;	//黑板	  全体学生类的对象共有
};

int Student::blackboard = 1;
int main()
{
    Student Cukor;
    Student Jack;
    //使用对象访问
    Cukor.ourBK();
    //不使用对象访问
    Student::ourBK();
    Jack.ourBK();
    Cukor.ourBK();
	return 0;
}

void Student::print()
{
    cout << "this is Student::print" << endl;
}
/*
输出结果:
	黑板上写了"某某某我喜欢你"
	黑板已经擦干净
	黑板上写了"某某某我喜欢你"
	黑板已经擦干净
*/

通过上面的代码就可以证明,静态函数成员是整个类共有的,不算某一个对象特有的。

类的友元

友元相当于朋友,一个东西被声明成友元,那么这个东西就可以访问得到这个类所有东西,就像是你交了一个好朋友,然后你就毫无保留的告诉你这个好朋友你的一切一样。C++的friend关键字是这样,但是现实生活中还是不要这样好,保留自己的一些隐私比较好,要不然显得自己很廉价。

友元的关键字:friend

被声明成友元的东西都不属于该类,声明为友元的作用主要是想打破类的权限限定,直接访问到类中的所有数据。

友元函数

简单来说,友元函数就是在类中用friend关键字修饰的函数就这个类的友元函数。

注意点:声明友元函数的时候,在友元函数的参数列表中要有对应的类的对象。

#include<iostream>
using namespace std;

class MM
{
public:
	//下面这个函数是MM类的友元函数
	friend void print(MM mm)		//参数列表里是MM类的对象,然后mm可以访问MM类的全部内容
	{
		//友元函数可以在类中实现,也可以在类外实现
		mm.name = "This is my friend";	//这里的访问是正确的,因为声明了是友元函数
		cout << mm.name << endl;
		mm.age = 18;
		cout << "He or she is " << mm.age << "years old" << endl;
	}
	friend void run(MM mm);
protected:
	string name="Alice";
	int age;
};

//类外实现的时候,去掉friend关键字
void run(MM mm)
{
    //这里的访问是正确的
	cout << mm.name << "跑起来了" << endl;
}
int main()
{
	MM mm;
    //单纯的想在这里访问MM类中的name是不可以的
    //mm.name="美女";  是错的
    //mm.age=19;   也是错的
	print(mm);
	run(mm);
	return 0;
}

友元类

跟友元函数一样,一个类可以声明另一个类是本类的友元类。若A类是B类的友元类,那么A类的所有成员函数都是B类的友元函数,都可以访问得到B类里面的所有东西。

class B
{
    ...
    friend class A;		//A类是B类的友元类
    ...
};

下面是测试代码

#include<iostream>
using namespace std;

class MM
{
public:
	friend class GG;	//声明GG类是MM类的友元,即GG和MM是朋友
	MM(string name,int age,int faceScore):name(name),age(age),faceScore(faceScore){}
	void printMM();
	
protected:
	string name;
	int age;
	int faceScore;
};

class GG
{
public:
	GG(string name,int age,int faceScore):name(name),age(age),faceScore(faceScore){}
	void callMM(MM mm);
protected:
	string name;
	int age;
	int faceScore;
};

int main()
{
	MM mm("Alice", 19, 100);
	GG gg("Cukor", 20, 60);
	gg.callMM(mm);
	return 0;
}

void MM::printMM()
{
	cout << "MM的信息如下:" << endl;
	cout << "姓名: " << this->name << endl;
	cout << "年龄: " << this->age << endl;
	cout << "颜值: " << this->faceScore << endl;
}

void GG::callMM(MM mm)
{
	//访问MM类中的数据成员没有任何问题
	cout << this->name << "叫" << mm.name << "出来玩" << endl;
	mm.printMM();		//调用MM类的成员函数,没有任何问题
}

关于友元还需要注意几点:

  • 友元关系不能传递:A是B的友元,B是C的友元,但如果没有声明A是C的友元的情况下,A和C没有任何关系。就像是生活中的例子一样,你和Cukor是朋友,Cukor和Jack是朋友,但是你和Jack不认识,那你和Jack就不是朋友。虽然你和Jack的共同朋友是Cukor。
  • 友元关系的单项的:A是B的友元,但B不一定是A的友元,除非声明。这个就像是在现实生活中的一样,小明拿小刚当朋友,小刚却不认为小明是自己的朋友。
  • 友元关系不会被继承:A是B的友元,A的派生类C和B不是友元关系。生活中的例子就是,小明和小刚是朋友,然后小明的儿子小强和小刚就不是朋友,当然如果声明了,是可以成为朋友的。但一生下来的时候肯定不是吧。
#include<iostream>
using namespace std;

class MM
{
public:
	friend class GG;
	void printMM()
	{
		cout << this->name << endl;
	}
protected:
	string name;
};

class GG
{
public:
	void callMM(MM mm)
	{
		//可以访问得到
		cout << this->name << "call"<<mm.name;
		mm.printMM();
	}
protected:
	string name;
};

class Son :public GG
{
public:
	void print(MM mm)
	{
		//访问不到,错误
		//cout << mm.name << endl;

	}
protected:
	int age;
};

int main()
{

	return 0;
}

类的常成员

使用const修饰的量就是一个常量,在初始化后就不能再改变。所以说一定要初始化。目的很简单,就是为了保护数据,防止数据不小心在程序运行的过程中改变。起到了保护的作用。

常数据成员

和一般的数据类型一样,在前面加了const修饰,那么这个数据成员就是一个常属性,定义的时候初始化,之后就不能修改了。

在类中的常数据成员只有两种初始化方式:

  • 直接在定义的时候初始化
  • 通过构造函数的初始化参数列表进行初始化
#include<iostream>
using namespace std;
class MM
{
public:	
	MM(string name,int age):name(name),age(age){}	
	MM(string name):name(name){}	
	void print()	
	{		
		cout << name << '\t' << age << endl;	
	}
protected:	
	const string name;	
	const int age = 18;
};

int main()
{	
	MM mm("Alice", 19);	
	mm.print();		//打印:Alice	19	
	MM mm2("Coco");	
	mm2.print();	//打印:Coco	18	
	return 0;
}

常函数成员

使用const修饰的函数成员就是常函数成员,常函数成员有以下特性:

  • 在当前函数中不能修改数据成员,无论是什么数据
  • const写在相应的函数的后面
  • 可以和普通的函数成员同时存在
  • 普通对象优先调用普通函数,没得选择的时候才会调用常函数成员
  • 常对象只能调用常函数成员
#include<iostream>
using namespace std;
class MM
{
public:	
	//使用初始化参数列表进行初始化	
	MM(string name,int age):name(name),age(age){}	
	//普通函数成员	
	void print()	
	{		
		age++;		
		cout << name << '\t' << age << endl;	
	}	
	//常函数成员	
	void print()const	
	{		
		//age++;	这里会报错,因为常函数成员中的数据不能被改		
		cout << name << '\t' << age << endl;	
	}
protected:	
	const string name;	
	int age;
};

int main()
{	
	MM mm("Alice", 19);	
	mm.print();		//调用的是普通成员函数	
	//打印:Alice		20	
	const MM mm2("Coco", 19);	
	mm2.print();	//调用的是常函数成员,因为mm2是常对象	
	return 0;
}

常对象

使用const修饰的对象就是常对象。

const int i=100;	//这个是一个常对象
//假设这里有一个MM类
const MM mm;		//这个是一个常对象
MM const mm2;		//这样写也是正确的,一般使用上面的写法

常对象是在定义时初始化,然后在这个对象的生命周期期间不能再修改对象里面的属性。常队形必须进行初始化。

常对象只能调用常函数成员不能调用非常函数成员。

#include<iostream>
using namespace std;
class MM
{
public:	
	MM(){}	
	MM(string name,int faceScore):name(name),faceScore(faceScore){}	
	void print()const	
	{		
		cout << "常函数成员" << endl;		
		cout << name << '\t' << faceScore << endl;	
	}	
	void print()	
	{		
		cout << "普通函数" << endl;		
		cout << name << '\t' << faceScore << endl;	
	}	
	void printData()	
	{		
		cout << "this is printData" << endl;		
		cout << name << '\t' << faceScore << endl;	
	}
protected:	
	string name;	
	int faceScore;
};

int main()
{	
	const MM mm;	
	MM const mm2;	
	mm.print();		//打印的是垃圾值	
	mm2.print();	//打印的是垃圾值	
	const MM mm3("Alice", 100);	
	mm3.print();	
	//mm3.printData();	
	//错误:对象含有与成员 函数 "MM::printData" 不兼容的类型限定符	
	MM mm4("Coco", 80);	//定义一个普通对象	
	mm4.printData();	//正确	
	return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-13 11:45:37  更:2021-08-13 11:46:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/26 17:44:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计