Visual C++基础 - 类的补充

1.7 静态类成员

        类的成员一般通过对象来访问,不可以通过类名直接访问。但是如果将类成员定义为静态类成员,则允许使用类名直接访问。静态类成员是在类成员定义前使用static关键字进行标识。

class CBook
{
public:
	static unsigned int m_Price; //  定义一个静态数据成员
};

        在定义静态数据成员时,通常需要在类外部对静态数据成员进行初始化。例如:

unsigned int CBook ::m_Price = 10;

        对于静态类成员,则不仅可以使用对象访问,也可以使用类名直接访问。

int main()
{
	CBook book;
	printf("%d\n", CBook::m_Price);
	printf("%d\n", book.m_Price);
	return 0;
}

        在一个类中,静态数据成员是被所有的类的对象所共享的,这就意味着无论定义多少个类对象,静态数据成员只有一份,同时,如果某个类对象改变了该静态数据成员,其他对象的静态数据成员也将会改变,因为是同一个静态数据成员(静态数据成员同时属于全世界~)。

        

class CBook
{
public:
	static unsigned int m_Price;
};
unsigned int CBook ::m_Price = 10;

int main()
{
	CBook book ,vbook;
	printf("%d\n", CBook::m_Price);
	printf("%d\n", book.m_Price);
	vbook.m_Price = 100;
	printf("%d\n", CBook::m_Price);
	printf("%d\n", book.m_Price);
	return 0;
}

        输出为:

对于静态类的数据成员,还需要注意以下几点;

(1)   静态数据成员可以是当前类的类型,而其他数据成员只能是当前类的指针或者引用类型。

        在定义类的成员时,对于静态数据成员,其类型可以是当前类的类型,而非静态数据成员则是不可以的,除非数据成员为当前类的指针或者引用类型。

(2)   静态数据成员可以作为成员函数的默认参数。

        在定义类的成员函数是,可以为成员函数指定默认参数,其参数的默认值也可以是类的静态数据成员,但是普通的数据成员则不能作为成员函数的默认参数。

1.8 嵌套类和局部类

嵌套类 : 一个A类中定义另外一个类B,B称之为嵌套类。

        嵌套类B对于外围类A,A通常是不能访问嵌套类B的私有成员,只有在定义嵌套类B时,将类A定义为类B的友元类,这就可以访问嵌套类的私有成员了。

局部类 : 将类的定义放置在函数中,这样的类称之为局部类。

        局部类中函数之外是不能被访问的,被局部封装在函数的局部作用域中,在局部类中,用户也可以再定义一个嵌套类。

1.9 类模板的定义和应用

        在介绍类模板之前,先来设计一个简单的单项链表。在链表的功能包括向尾节点添加数据,遍历链表中的节点、在链表结束时释放所有的节点。代码如下:

#include "stdafx.h"
class CNode									//定义一个节点类
{
public:
	CNode *m_pNext;							//定义一个节点指针,指向下一个节点
	int   m_Data;								//定义节点的数据
	CNode()									//定义节点类的构造函数
	{
		m_pNext = NULL;						//将m_pNext设置为空
	}
};


class CList									//定义链表类CList类
{
private:
	CNode *m_pHeader;							//定义头节点
	int   m_NodeSum;							//节点数量
public:
	CList()									//定义链表的构造函数
	{
		m_pHeader = NULL;						//初始化m_pHeader
		m_NodeSum = 0;						//初始化m_NodeSum
	}
	CNode* MoveTrail()							//移动到尾节点
	{
		CNode* pTmp = m_pHeader;				//定义一个临时节点,将其指向头节点
		for (int i = 1; i<m_NodeSum; i++)				//遍历节点
		{
			pTmp = pTmp->m_pNext;				//获取下一个节点
		}
		return pTmp;							//返回尾节点
	}
	void AddNode(CNode *pNode)					//添加节点
	{
		if (m_NodeSum == 0)					//判断链表是否为空
		{
			m_pHeader = pNode;				//将节点添加到头节点中
		}
		else									//链表不为空
		{
			CNode* pTrail = MoveTrail();			//搜索尾节点
			pTrail->m_pNext = pNode;			//在尾节点处添加节点
		}
		m_NodeSum++;						//使链表节点数量加1
	}
	void PassList()								//遍历链表
	{
		if (m_NodeSum > 0)						//判断链表是否为空
		{
			CNode* pTmp = m_pHeader;			//定义一个临时节点,将其指向头节点
			printf("%4d", pTmp->m_Data);			//输出节点数据
			for (int i = 1; i<m_NodeSum; i++)			//遍历其他节点
			{
				pTmp = pTmp->m_pNext;			//获取下一个节点
				printf("%4d", pTmp->m_Data);		//输出节点数据
			}
		}
	}
	~CList()									//定义链表析构函数
	{
		if (m_NodeSum > 0)						//链表不为空
		{
			CNode *pDelete = m_pHeader;			//定义一个临时节点,指向头节点
			CNode *pTmp = NULL;				//定义一个临时节点
			for (int i = 0; i< m_NodeSum; i++)			//遍历节点
			{
				pTmp = pDelete->m_pNext;		//获取下一个节点
				delete pDelete;					//释放当前节点
				pDelete = pTmp;				//将下一个节点设置为当前节点
			}
			m_NodeSum = 0;					//将m_NodeSum设置为0
			pDelete = NULL;					//将pDelete置为空
			pTmp = NULL;						//将pTmp置为空
		}
		m_pHeader = NULL;						//将m_pHeader置为空
	}
};



下面顶一个链表对象,向其中添加节点,然后遍历链表节点。

int main(int argc, char* argv[])
{
	CList list;									//定义链表对象
	for (int i = 0; i<5; i++)							//利用循环向链表中添加5个节点
	{
		CNode *pNode = new CNode();			//构造节点对象
		pNode->m_Data = i;						//设置节点数据
		list.AddNode(pNode);					//添加节点到链表
	}
	list.PassList();								//遍历节点
	printf("\n");								//输出换行
	return 0;
}

        分析上述代码中顶一个链表类CList,一个最大的缺陷就是不够灵活,其节点只能是CNode类型,为了让CList能够适应各种类型的节点,一个最简单的方法,就是使用类模板。类模板的定义与函数模板类似,以关键字template开始,其后由尖括号<>构成的模板参数。

        下面重新定义CList,以类模板的形式进行改写。

        template <class Type>                            //定义类模板

// ClassTemplate.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

template <class Type>							//定义类模板
class CList									//定义CList类
{
private:
	Type *m_pHeader;							//定义头节点
	int   m_NodeSum;							//节点数量
public:
	CList()									//定义构造函数
	{
		m_pHeader = NULL;						//将m_pHeader置为空
		m_NodeSum = 0;						//将m_NodeSum置为0
	}
	Type* MoveTrail()							//获取尾节点
	{
		Type *pTmp = m_pHeader;				//定义一个临时节点,将其指向头节点
		for (int i=1;i<m_NodeSum;i++)				//遍历链表
		{
			pTmp = pTmp->m_pNext;				//将下一个节点指向当前节点
		}
		return pTmp;							//返回尾节点
	}
	void AddNode(Type *pNode)					//添加节点
	{	
		if (m_NodeSum == 0)					//判断链表是否为空
		{
			m_pHeader = pNode;				//在头节点处添加节点
		}
		else									//链表不为空
		{
			Type* pTrail = MoveTrail();			//获取尾节点
			pTrail->m_pNext = pNode;			//在尾节点处添加节点
		}
		m_NodeSum++;						//使节点数量加1
	}
	void PassList()								//遍历链表
	{
		if (m_NodeSum > 0)						//判断链表是否为空
		{
			Type* pTmp = m_pHeader;			//定义一个临时节点,将其指向头节点
			printf("%4d",pTmp->m_Data);			//输出头节点数据
			for (int i=1;i<m_NodeSum;i++)			//利用循环访问节点
			{
				pTmp = pTmp->m_pNext;			//获取下一个节点
				printf("%4d",pTmp->m_Data);		//输出节点数据
			}
		}
	}
	~CList()									//定义析构函数
	{
		if (m_NodeSum > 0)						//判断链表是否为空
		{
			Type *pDelete = m_pHeader;			//定义一个临时节点,将其指向头节点
			Type *pTmp = NULL;				//定义一个临时节点
			for(int i=0; i< m_NodeSum; i++)			//利用循环遍历所有节点
			{
				pTmp = pDelete->m_pNext;		//将下一个节点指向当前节点
				delete pDelete;					//释放当前节点
				pDelete = pTmp;				//将当前节点指向下一个节点
			}
			m_NodeSum = 0;					//设置节点数量为0
			pDelete = NULL;					//将pDelete置为空
			pTmp = NULL;						//将pTmp置为空
		}
		m_pHeader = NULL;						//将m_pHeader置为空
	}
};
class CNode									//定义一个节点类
{
public:
	CNode *m_pNext;							//定义一个节点指针,指向下一个节点
	int   m_Data;								//定义节点的数据
	CNode()									//定义节点类的构造函数
	{
		m_pNext = NULL;						//将m_pNext设置为空
	}
};

        每个模板参数必须由Class或者typename标识,不能够利用一个class或者typename关键字定义多个模板参数。

        上述代码利用类模板对链表类CList进行了修改,实际上是在原来链表的基础上将链表中出现CNode类型的地方替换为模板参数type。下面可以再定义一个CNet类,演示类模板CList是如何食用不同节点类型的。



class CNet									//定义一个节点类
{
public:
	CNet *m_pNext;							//定义一个节点类指针
	char   m_Data;							//定义节点类的数据成员
	CNet()									//定义构造函数
	{
		m_pNext = NULL;						//将m_pNext置为空
	}
};
int main(int argc, char* argv[])
{
	CList<CNode> nodelist;						//构造一个类模板实例
	for(int n=0; n<5; n++)						//利用循环向链表中添加节点
	{
		CNode *pNode = new CNode();			//创建节点对象
		pNode->m_Data = n;					//设置节点数据
		nodelist.AddNode(pNode);				//向链表中添加节点
	}
	nodelist.PassList();							//遍历链表
	printf("\n");								//输出换行
	CList<CNet> netlist;						//构造一个类模板实例
	for(int i=0; i<5; i++)							//利用循环向链表中添加节点
	{
		CNet *pNode = new CNet();				//创建节点对象
		pNode->m_Data = 97+i;					//设置节点数据
		netlist.AddNode(pNode);					//向链表中添加节点
	}
	netlist.PassList();							//遍历链表
	printf("\n");								//输出换行
	return 0;
}

输出如下:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Microsoft Visual C++ 2015-2019 Redistributable是一款用于支持安装和运行使用Microsoft Visual Studio开发的应用程序所需要的运行时组件。该软件包提供了与C++相关的一系列库文件,如C++运行时库、标准C++库、ATL库、MFC库等。 这个软件包的安装可以在运行使用Visual Studio开发的应用程序时自动进行,也可以手动下载和安装。它的作用是为了让用户在运行这些应用程序时不再需要单独安装Visual Studio开发环境,只需要安装这个Redistributable即可。 Microsoft Visual C++ 2015-2019 Redistributable的主要特点包括: 1. 支持多个版本:它同时支持Visual C++ 2015、2017和2019的各个版本,包括x86和x64两种体系结构。 2. 系统兼容性:适用于多种Windows操作系统,包括Windows 7、Windows 8、Windows 10等系统。 3. 占用空间小:安装包的大小相对较小,不会占用过多磁盘空间。 4. 增强稳定性:安装该运行时组件可以增强应用程序的稳定性和安全性,提高其兼容性和性能。 5. 升级和修复功能:当某个应用程序需要升级或修复时,Redistributable会自动检测并提供相应的版本更新。 总的来说,Microsoft Visual C++ 2015-2019 Redistributable是Microsoft为了方便用户安装和运行使用Visual Studio开发的应用程序而提供的一款运行时组件。它能够提供必要的库文件支持,提高应用程序的兼容性和稳定性,为用户提供更好的使用体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值