记录一下自己学习c++的一些坑吧,也是熟悉一下用CSDN写Blog
欢迎使用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;
}