2020-12-01

欢迎使用Markdown编辑器

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


动态链表

一、用循环创建一个定长链表

#include<iostream>
using namespace std;

struct node
{
	int data;
	node* next;
};


int main()
{
	node* p;
	node* pre;
	node* head = new node; //创建一个头节;
	head->data = NULL;//初始化头节的data域
	pre = head; //让pre指针指向头节
	for (int i = 0; i < 5; i++)
	{
		pre->next = new node;
		p = pre->next; //p指向了新节
		cout << "输入数据对链表赋值" << endl;
		cin >> p -> data;
		pre = p;
		//这里一共创建了5个有效的链表节(包括了尾节)
	}

	//再写一个编历链表检验以上代码的正确性:
	p = head->next; //把p指针指向头节,拿到第一节的数据;
	while (p->next != NULL)
	{
		cout << p->data << endl;
		p = p->next;
	}
	return 0;
}

构造函数的一些理解


提示:以下是本篇文章正文内容,下面案例可供参考

一、前言

构造函数:顾名思义,就是 创造一个 类的实例时 使用的一个函数。
具体的 构造函数 实现过程在下面的 几种调用构造函数的方法 会讲我自己的一些理解
(本人小白,轻喷,也感谢指出错误)

二、三种构造函数

1.无参构造函数(默认构造函数)

代码如下(示例):

class person
{
public:
	person() //这是一个无参构造函数
	{

	}
};

任何一个类创建时,若没有对其定义构造函数,系统会默认的调用 空构造函数
这里的 演示构造函数 和 默认的构造函数 无二。

在运行一个例子

#include<iostream>
using namespace std;

class person
{
public:
	person() //这是一个无参构造函数
	{
		cout << "这是一个无参构造函数" << endl;
	}
};


int main()
{
	person a;

}

输出结果如下:

这是一个无参构造函数

C:\Users\Hasee\source\repos\classic\Debug\classic.exe (进程 3176)已退出,代码为 0。
按任意键关闭此窗口. . .

2.有参构造函数

代码如下(示例):

这里使用的是整型参数,当然你可以使用其他的数据类型作为参数带入

#include<iostream>
using namespace std;

class person
{
public:
	person() //这是一个无参构造函数
	{
		cout << "这是一个无参构造函数" << endl;
	}
	person(int)//此处可以发生 构造函数 重载
	{
		cout << "这是有参构造函数" << endl;
	}
};


int main()
{
	
	person a(10);//重载后选择了上面的第二个构造函数执行

}

输出结果如下:

这是有参构造函数

C:\Users\Hasee\source\repos\classic\Debug\classic.exe (进程 24380)已退出,代码为 0。
按任意键关闭此窗口. . .

这里就实现了一个参数构造函数的调用

3.拷贝函数的调用

首先先调用一下默认的拷贝函数吧

#include<iostream>
using namespace std;

class person
{
public:
	person() //这是一个无参构造函数
	{
		cout << "这是一个无参构造函数" << endl;
	}
	person(int)
	{
		cout << "这是有参构造函数" << endl;
	}
	int age = 10;

};


int main()
{
	
	person a(10);
	cout << "打印 a 的age数据" << a.age << endl;
	person b(a);
	cout << "打印 b 的age数据" << b.age << endl;
}

输出结果如下:

这是有参构造函数,现在这是废话
打印 a 的age数据10
打印 b 的age数据10

C:\Users\Hasee\source\repos\classic\Debug\classic.exe (进程 26004)已退出,代码为 0。
按任意键关闭此窗口. . .

再写一个我们自己创建的拷贝函数,此时原有的拷贝函数不再被调用,转而调用我们自己写的拷贝函数

#include<iostream>
#include<string>
using namespace std;

class person
{


public:
	person() //这是一个无参构造函数
	{
		//cout << "这是一个无参构造函数" << endl;
	};
	person(int)
	{
		//cout << "这是有参构造函数" << endl;
	};
	person(const person& a)
	{
		//cout << "这是拷贝构造函数" << endl;
		age = a.age; //这里只写了对age数据的拷贝 , 没有对类内的name的数据进行拷贝
	};
	int age = 10;
	string name = "kazen";

};


int main()
{
	person a;
	a.name = "他不叫kazen";
	a.age = 100;             //这里把a的name和age给改了,看看会不会被拷贝到b
	cout <<"输出a的age" << a.age<<endl<<"输出a的name "<< a.name<<endl;
	
	person b = a;//注意这里person b(a); 
	//构造函数传入的a 并非是a的值 ,而是 一个名 为 a 的 a的引用 。
	// 有点绕但是没有关系 ,
	//看到后面的构造函数的具体实现你就会明白了。
	cout << "输出b的age" << b.age << endl << "输出b的name " << b.name;
}

输出结果如下:

输出a的age100
输出a的name 他不叫kazen
输出b的age100
输出b的name kazen
C:\Users\Hasee\source\repos\classic\Debug\classic.exe (进程 9208)已退出,代码为 0。
按任意键关闭此窗口. . .

发现b的age 拷贝了a的age,但是name数据没有发生拷贝。
说明的原有的拷贝函数对类内的所有数据进行了拷贝,
此处手打的代码没有拷贝。

该处使用的url网络请求的数据。

三、构造函数的调用

1.构造函数调用的三种写法

int main()
{
	person a(10);          //括号法
	person a = person(10); //显示法
	person a = 10;         //隐式转化法
}

以上都是 给构造函数 person(int) 传入参数的三种形式

2.拷贝构造函数的一个隐性调用

先上例子:

#include<iostream>
#include<string>
using namespace std;

class person
{


public:
	person() //这是一个无参构造函数
	{
		cout << "这是一个无参构造函数" << endl;
	};
	person(int)
	{
		cout << "这是有参构造函数" << endl;
	};
	person(const person& a)
	{
		cout << "这是拷贝构造函数" << endl;
		age = a.age; //这里只写了对age数据的拷贝 , 没有对类内的name的数据进行拷贝
	};
	int age = 10;
	string name = "kazen";

};

void dowork(person a)
{
	//空语句就行
}


int main()
{
	person a;
	dowork(a);
	return 0;

}

输出结果:

这是一个无参构造函数
这是拷贝构造函数

C:\Users\Hasee\source\repos\classic\Debug\classic.exe (进程 20948)已退出,代码为 0。
按任意键关闭此窗口. . .

观察到在程序中调用了一个拷贝构造函数,问题出在

	dowork(a);

这里的dowork函数的运行时 传入了 a的一个引用 创造了一个 副本a
等效 person a = a;
左侧是一个副本 右侧是一个 a的引用
解释来说就是 借用了 传入a的引用 对 副本内的a 使用拷贝构造函数进行了初始化

3.对构造函数的理解

是提供可以传入参数,初始化一个类的实例的方法。
如:


四、贝构造函数的深拷贝与浅拷贝


下面是一个深拷贝的例子:

#include<iostream>
using namespace std;

class test
{
public:
	int* p_data;//在类内定义一个指针用于指向 在堆区保存的一个整型数据
    
	//定义一个有参构造函数,方便我们为创建的第一个 test01 实例赋值			
	test(int a)
	{
		p_data = new int(a);
	}
	
	//定义一个深拷贝的构造函数
	test(const test &A) //拷贝函数,传入一个test类型的引用
	{
		p_data = new int(*A.p_data); //这里new里带入的是 A指向堆区指针的解引用 
		                             //把堆区的数据传入了,并在堆区开辟了一块新的内存。
		                             //并且类内的指针指向 这块新内存
	}


	//利用析构函数回收内存 释放掉堆上的内存 当类的寿命结束的时候 只清空例子里的 一个地址数据,堆上的数据没有释放
	~test()
	{
		if (p_data != NULL)
		{
			delete p_data; 
			p_data = NULL;//将悬垂指针置空 避免野指针出现
		}
    }


};

int main()
{
	test t1(10);
	cout << *t1.p_data<<endl; //尝试下对 t1 在堆区的数据的访问
	test t2(t1);       
	cout << *t2.p_data; //尝试对t2 在堆区的数据的访问
	return 0;
}



总结

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值