C++学习笔记(7)

本文详细介绍了C++中类的组合,包括以另一个类为数据类型时的构造与析构顺序问题,以及类中类的概念和实现。同时,探讨了类中的枚举及默认函数,强调了权限限定和访问方式。通过实例代码解析了构造与析构的顺序,以及如何在类中创建和使用迭代器。最后,讨论了类中枚举的访问规则和默认函数的特性。
摘要由CSDN通过智能技术生成

目录

一.类的组合

1.以另一个类为数据类型

2.构造与析构顺序问题

二.类中类

三.类中的枚举及默认函数

1.类中的枚举

2.类中默认的函数


一.类的组合

1.以另一个类为数据类型

注意:构造函数必须采用初始化参数列表的写法!且要用分支类的构造函数的写法,举例说明:

class A
{
public:
	A(string name,int age):name(name),age(age){}
protected:
	string name;
	int age;
};
class B
{
public:
	B(string name, int age, int year) :a(name, age), year(year){}
protected:
	int year;
	A a;
};

可以看到,类B中要初始化数据类型A时,也调用了A的构造函数。注意,这里的意思不是说以另一个类为数据类型,所有的参数都要用初始化参数列表的形式初始化,只是分支类的初始化需要,所以我们也可以这样写:

B(string name, int age, int year) :a(name, age)
{
	this->year = year;
}

那B类中的A的访问权限限定还存在吗?答案是肯定的,来看以下代码:我们在A设置了两个功能相同的打印函数,一个放在public,一个放在protected,看一下他们有什么不同:

class A
{
public:
	A(string name,int age):name(name),age(age){}
	void printData1()
	{
		cout << name << " " << age << endl;
	}
protected:
	void printData2()
	{
		cout << name << " " << age << endl;
	}
	string name;
	int age;
};
class B
{
public:
	B(string name, int age, int year) :a(name, age)
	{
		this->year = year;
	}
	void printB()
	{
		a.printData1();
		a.printData2(); //没有权限,无法访问
		cout << year << endl;
	}
protected:
	int year;
	A a;
};
int main()
{
	B b("小蓝", 18, 7);
	b.printB();
}

可以看到,我们打出来的时候编译器报错显示无法访问,因为A的对象a对于A来说是属于类外的,不可直接访问保护属性下的数据成员、成员函数,a对象调用A的属性也受权限限定,因此要在public中提供接口来访问。

2.构造与析构顺序问题

前面我们分析了一些常见的构造与析构顺序问题的分析,详情可见:构造函数与析构函数

今天我们补充一点,那就是类的组合中的构造与析构的顺序问题,同样的,我们来分析下面的代码:

class A
{
public:
	A(string name):name(name)
	{
		cout << "我构造了A" << endl;
	}
	~A()
	{
		cout << "我析构了A" << endl;
	}
protected:
	string name;
};
class B
{
public:
	B(string name) :name(name)
	{
		cout << "我构造了B" << endl;
	}
	~B()
	{
		cout << "我析构了B" << endl;
	}
protected:
	string name;
};
class C
{
public:
	C(string name) :name(name)
	{
		cout << "我构造了C" << endl;
	}
	~C()
	{
		cout << "我析构了C" << endl;
	}
protected:
	string name;
};
class D
{
public:
	D(string aname,string bname,string cname) :b(bname),c(cname),a(aname)
	{
		cout << "我构造了D" << endl;
	}
	~D()
	{
		cout << "我析构了D" << endl;
	}
protected:
	A a;
	B b;
	C c;
};
int main()
{
	D d("A", "B", "C");
	return 0;
}

最后的打印结果是:

可以看到,构造的顺序跟初始化参数列表的顺序是没有关系的,构造的顺序跟定义数据的顺序有关,我们先定义了ABC,然后构造出这三个之后最后构造出一个包含他们三个的完整对象d,之前说过,正常情况下析构顺序与构造顺序相反,这里也同样适用,所以是 “DCBA” 。

二.类中类

类中类跟类的组合不同,类中类的意思是有一个类的定义是在类中的,而类的组合只是使用了类当数据成员。类中类的访问依然受权限限定,且访问方式需要类名限定。

我们以手写一个简单的迭代器(用类模仿指针的行为)的方式举例,来遍历链表中的数据:

第一步:写好链表的基本结构。

//之前说过,结构体跟类的使用是相关的,由于数据都是共有的,所以用结构体写
struct Node
{
	int data;
	Node* next;
	Node()  //无参数以创建表头
	{
		this->next = nullptr;
	}
	Node(int data)  //有参数来创建节点
	{
		this->data = data;
		this->next = nullptr;
	}
};

第二步:在List类中写好链表的基本操作,然后创建迭代器的小框架。

class List
{
public:
	List()  //创建链表
	{
		headNode = new Node;
	}
	void push_head(int data)  //头插法
	{
		Node* newNode =new Node(data);
		newNode->next = headNode->next;
		headNode->next = newNode;
	}
protected:
	Node* headNode;
public:
	class iterator  //迭代器
	{
	public:

	protected:

	};
};

第三步:补充迭代器中的操作,主要是对一些运算符的重载。

class List
{
public:
	List()  //创建链表
	{
		headNode = new Node;
	}
	void push_head(int data)  //头插法
	{
		Node* newNode =new Node(data);
		newNode->next = headNode->next;
		headNode->next = newNode;
	}
protected:
	Node* headNode;
public:
	class iterator  //迭代器
	{
	public:
		iterator(Node* pMove = nullptr):pMove(pMove){}
		//实现两个指针的赋值操作
		void operator=(Node* object)
		{
			pMove = object;
		}
		//两个指针之间指向的不等
		bool operator!=(Node* object)
		{
			return pMove != object;
		}
		//指针++前置操作重载,返回的是对象
		iterator operator++()
		{
			pMove = pMove->next;
			return iterator(pMove);
		}
		Node*& operator*()
		{
			return pMove;
		}
	protected:
		Node* pMove;
	};
	//获取开始的位置
	Node* begin()
	{
		return headNode->next;
	}
	//获取结束的位置
	Node* end()
	{
		return nullptr;
	}
};

第四步:输入验证代码。

int main()
{
	List list;
	for (int i = 0; i < 5; i++)
	{
		list.push_head(i);
	}
	List::iterator iter;
	for (iter = list.begin(); iter != list.end(); ++iter)
	{
		cout << (*iter)->data << endl;
	}
}

输出如下:

 可以看到,出现了我们想要的打印结果。

三.类中的枚举及默认函数

1.类中的枚举

同样,类中的枚举依然受访问权限的限制。

class  A
{
public:
	enum time { first, second };
protected:
	enum date { one, two, three };           //类中的枚举类型受权限限定

};
int main()
{
	one;  //直接访问报错
	cout << A::one; //受权限限定报错
	cout << A::first;//没报错
}

2.类中默认的函数

class A
{
public:
	A() = default;    //构造函数
	A(A& object) = default; //拷贝构造函数
	A& operator=(A& object) = default;    //返回类型:A类对象的引用 赋值的重载
	~A() = default;   //析构函数
};

注意:普通函数是没有默认的函数的。

好了,今天的总结就到这,下篇更新C++类的继承的用法!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值