- c++基础
- 头文件
- 调试时界面一闪而过
- cin 输入
- cout输出
- gmpz函数
- endl-高级换行
- using namespace std 空间命名
- 高级注释符-#if 0 ... #endif
- typedef 创建新的自定义类型的名字
- 取数据类型LOWORd(), HIWORd(), LOBYTE(), HIBYTE()
- 指针 int* ptr
- 结构体 struct My_Type
- 引用 int &=xx
- 函数升级版
- 类
- __1-1导入部分__
- ___2-1访问权限___
- ___3-1struct与class的区别___
- ___1-2-对象的初始化与清理___
- __1-2-1-导入__
- _构造函数_
- _析构函数_
- ___1-2-2构造函数的分类以及调用___
- 大致框架
- 无参数构造
- 有参数构造
- 普通构造
- 拷贝构造
- 调用方式-括号法
- 调用方式-显示法
- 调用的隐士法
- ___1-2-3-拷贝构造函数调用的时机___
- ___构造函数的调用规则___
- 深度拷贝与浅拷贝
- 浅拷贝
- 深度拷贝
- 初始化列表给类赋初值
- 类对象作为类成员(嵌套式类)
- 静态成员
- 成员变量与成员函数分开存储
- C++一些高级的应用
- 暂停 pause
- 清屏 cls
#include
using namespace std;
i input
o output
stream 流
你要高大上点
cin.clear(); // 清空缓存
cin.sync(); // 清空缓存
cin.get(); // 接收键盘输入
再组后用这几个函数就
你要简单点?
在最后写
getchar();
然后最后输入一个char的字符来结束调试
你要专业点?
//引入头文件 #include或者 #include //在代码最后写 system("pause"); //于是调试到最后需要你enter才会结束调试
不管它是什么类型,输出就可了
cin 输入其实输入的话,相比C语言,它少了一些格式化的 *** 作
cin>>x; "不管x是什么类型,只管往里面输入就"
std::__cxx11::basic_string
std::__cxx11::basic_string
像这些C++函数,你只需要看最后一句就可以了!最后一句就是它调用的函数
这些函数一般可以实现指针的传递,动态内存分配…
如何分析一个陌生的东西,还比
cout输出cout << dx; cout<<"Please input an int number:"<不同于C语言还要去格式化一下%d,%p,%c
相比与C语言的输出cout< gmpz函数__gmpz_init_set_str(v5, “65537”, 10LL);
endl-高级换行
东西,他确实是一个函数,点进去看,啥也没有,其实这更加确定了它是一个系统函数!系统函数就去百度呗,然后看它是什么作用使用 endl 时会刷新缓冲区,使得栈中的东西刷新一次,而不是仅仅换行的 *** 作
这么比喻std::cout << std::endl;是由2个部分构成,一个换行 *** 作,一个刷新缓冲区的 *** 作构
//flush应该是刷新的意思 td::cout << 'n' << std::flush;或者说是这个
std::cout << 'n'; std::fflush(stdout);其实有时候你不需要换行与刷新的 *** 作…于是这个endl的效率当然没’n’它的效率高,造成速度低慢…取决于你对程序的严谨性,想用endl就用呗
using namespace std 空间命名using namespace std 到底是什么意思??
声明一个命名空间(称之为房子)的意思
就是声明这个房子的名字…这个房子就是我的了.它的名字ID是我确认的using namespace std 其中的std是官方的房子…也就是说谁都可以用它
啰嗦了一大堆,该说回来了
std::
std 表示是 C++ 的标准命名空间,就是编译系统自带有的,按 C++ 标准定义好了的。
Eg:
我定义2个房子
using namespace 李四家
using namespace 张三家我分别再仓库里面放了2个一模一样名字的变量-看门狗Single_Dog
using namespace 李四家 : : Single_Dog
using namespace 张三家 : : Single_Dog
名字都是Single_Dog看门狗…但是他们的主人不一样,所属对象不一样比如,在使用输出 std::cout 时,如果它达不到我们想要的效果,我们也可以自己定义一个名字空间。
高级注释符-#if 0 … #endif
取名 myspace,再在这个空间里写一个 cout 函数来实现。调用时,就成了 myspace::cout我们可以使用 #if 0 … #endif 来实现注释,且可以实现嵌套,格式为:
#if 0
code代码段
#endif
那里的
0好比一个开关…0代表它是注释,关闭执行//#if 0 来屏蔽测试代码。
1好比打开开关…执行注释中的代码…//#if 1 来执行测试代码
#if xx
xxx可以条件语句。
下面的代码
如果 Button
条件为 True 执行 code1 ,
条件为 False执行 code2
#if Button
code1
#else
code2
#endif#includetypedef 创建新的自定义类型的名字using namespace std; int main() { //#与if挨在一起 //#endif也在挨在一起 #if 0 printf("you find men"); #endif printf("%s","you catch me"); cin.get(); } 您可以使用 typedef 为一个已有的类型取一个新的名字。
typedef type(类型) newname(名字);
Eg:
typedef char dqx_zj;
于是以前你用char var
现在你可以
dqx_zj var
于是你就把自定义的名字换了一下罢了
取数据类型LOWORd(), HIWORd(), LOBYTE(), HIBYTE()LOWORd(), HIWORd(), LOBYTE(), HIBYTE()
这些数据可能对针对与4字节的对象,好比一个int型的LO是低,反之HI是高
LOWORD意思就是取4字节的低位2字节,毕竟WORD是2字节的
HIWORD意思就是取4字节的高位2字节
LOBYTE就是默认取低位2字节中取低位1字节
HIBYTE就是默认取低位2字节的高位1字节其实他们都有定义的
我们一LOBYTE与HIBYTE为例子#define LOBYTE(w) ( (BYTE) ( ( (DWORD_PTR) (w) ) & 0xff)) #define HIBYTE(w) ( (BYTE) ( ( ((DWORD_PTR) (w) ) >> 8) & 0xff))上面的w就是你的参数,
然后你自己运行一下代码#include指针 int* ptr#include #include int main() { unsigned int data = 305419896;//0x12345678 unsigned short Two_Byte_High= HIWORD(data); // 取高16位 unsigned short Two_Byte_Low_= LOWORD(data); // 取低16位 // result: 0x1234 printf("0x1234 5678 的 高位2字节 0x%xn",Two_Byte_High); // result: 0x5678 printf("0x1234 5678 的 低位2字节 0x%xn",Two_Byte_Low_); unsigned char One_Byte_High = HIBYTE(data); // 取高8位 unsigned char One_Byte_Low_ = LOBYTE(data); // 取低8位 // result: 0x56 printf("0x1234 5678 的 高位1字节 0x%xn",One_Byte_High); // result: 0x78 printf("0x1234 5678 的 低位1字节 0x%xn",One_Byte_Low_); system("pause"); return EXIT_SUCCESS;//#define EXIT_SUCCESS 0 } 1-1-导读
指针==地址,
- 定义指针
类型 * 指针的名字
Eg
int *my_ptr
- 取地址:
指针 = &变量的名称
Eg:
my_ptr=&my_var;
- 使用指针
_* _指针名字
- 重点
我们可以用指针间接访问与修改它1-2-指针长度
在32位的 *** 作系统下,指针的长度就是4字节
在64位的 *** 作系统下,指针的长度就是8字节
32位的指针 0x40245632
64位的指针 0x1234567812345678
1-3-空指针
当地址是0就是空指针,别且它是不可以被访问的
可以用来初始化
NULL就是啥也没有的意思
小插曲
Eg:
int *p=NULL另外我们还有一种指针初始化的方式
这里有一个强制类型转化
1-4总结
1-5-野指针
开了一间房却去了另外一间房子
上面p地址指向一块未知区域
2-const修饰指针
分为3种类型
常量指针
指针常量
以上2种的mix
2-1第一组类型:常量指针
const修饰指针 叫常量指针
const在前,类似于
const(int * My_Ptr)于是指向的数据是无法改变的const int * my_ptr 常量+指针 const紧挨着int,int数据不可改它有什么特性?
- 它指向地址对应的数据是不可以修改的…意思就是好比pointer指向数据var=100,那么我们无法通过const指针去修改数据100
- 虽然是const,但是它可以改变指向的地址,好比它可以指向A也可以指向B,就是无法改变它指向的地址对应的数据`
红框数据不可修改…黑色箭头是合法指向2-2第二种类型:指针常量
类似与int * (const My_Ptr)
int * const My_Ptr 指针+常量 const 紧挨*指针 指针不可修改特点
指向不可修改
指向的值可以修改
红色不可指向
黑色数据可修改2-3类型三 -->指针常量与常量指针的混合体
const int * const My_ptr指向的数据与指针都不可以修改
关于指针的调用
*pre不仅仅是一个值,而是对应地址的值…我们改变它,其实是改变它对应地址的值
结构体 struct My_Type
1-1初级部分
如何理解这个自定义
我们定义一个数据类型,名字叫xxx
其实这个xxx类似是一些类型的集合
我们可以通过这个xxx类型调用那些已知类型上代码
struct My_Type { int Age; double High; double Weight; char * name; };于是你定义了一种类型,名字叫做My_Type,这种类型可以与Int,char
,double…等类型平起平坐…
比如你可以int var当然也可以My_Type var
你在调用var变量是会有所不同可以看出.你自己新定义的类型My_Type其实是里面int,double,char的集合
关于
1-2结构体的声明会有3种方式
无论哪种法式,你都要新定义类型struct My_Type { int Age; double High; double Weight; char * name; };请注意
结构体声明结束后会有一个分号;以表示结束的意思
对于C++类的话也是一样的,最后都会有个分号;结尾再是
1-1-1方式一
My_Type var; var.Age=20; var.High=165; var.Weight=116; var.name="D9x";1-1-2方式二
My_Type var={20,16,116,"D9x"};1-1-3方式三
struct My_Type { int Age; double High; double Weight; char * name; } var;
2-1结构体与数组
其实它的结构体定义还是一样的…只不过用它作为类型时,我们可以去定义一个数组罢了
首先还是一样的struct My_Type { int Age; double High; double Weight; char * name; } var;然后我们要去
2-2定义一个数组My_Type MyArr[3]= { {18,178,166,"一号"}, {19,189,123,"二号"}, {20,168,144,"三号"}, }2-3如何访问它?
同样是用点的 *** 作符My_Arr[i].name My_Arr[i].Age My_Arr[i].Weight如何遍历结构体数组,其实和一般的数组遍历其实是一样的
for(int i=0;i<3;i++) printf("%d %d %d %d",My_Arr[i].Age,My_Arr[i].Weight,My_Arr[i].High);
3-1结构体指针
先给一个图
我们这里要
3-2引入一个 *** 作符->
它可以指向结构指针对应的数据
比如ptr->Age,所以有了->,我们就不再需要*来指向数据了
其实的话…其它的定义都是一样的
先还是定义结构体struct My_Type { int Age; double High; double Weight; char * name; } ;然后是
3-3定义指针?
指针类型是什么?
当然是那个集合体的类型,也就是你自己定义的类型…My_Type var={20,16,116,"D9x"}; My_Type *My_Pt=&var; //于是可以调用指针 printf("%d %s",My_Ptr->Age,My_Ptr->name);
4-1结构体嵌套结构体
其实与函数调用差不多吧…
函数里面又去调用另外一个函数
这里其实涉及一个逻辑的包含关系
好比爸爸比儿子大一级,同时呢爸爸与儿子的属性又是差不多的…因为他们都有age,name,weight.high上代码
struct chld { int Age; double High; double Weight; char * name; } ; //其实上面定义了一个子结构 //下面定义父结构 struct Father { int Age; double High; double Weight; char * name; chld son;//这里定义了一个嵌套结构体 };调用的话也很简单…
Father Father_var; Father_var.Age=45; Father_var.high=160; //.... Father_var.son.Age=18; Father_var.son.name="D9x";值得我们注意的是…子结构一定要在父结构之前先定义…当然这是一个相对关系…
5-1结构体做函数的参数
其实可以类比一下swapt函数,就是你自己之前写的那个函数…里面涉及了一些关于值得传递与函数地址得传递
你传进去的是你自定义得类型…是一个类型的集合
上代码struct Father { int Age; double High; double Weight; char * name; }; Father my_arr={12,150,80,"哆啦"}; void fun1(father* data) { data->name="D9x"; //这里通过了地址改变了实参的值 printf("%d %s",data->Age,data->name); } void fun2(father data) { printf("%d %s",data->Age,data->name); //如果这里去改变data的值的话,不会改变实参的值 }
6-1结构体中的const
其实这个功能就是为了不然使用者修改数据罢了
来一个图片你且讲解一下
在上面中,我们用到了函数的打印…为什么要传递进去指针而不就传递值进去,这2种方式的效果是一样的,但是资源的消耗却不一样
如果你传递值进去的话…函数的调用其实是拷贝数据…你调用1000次,拷贝1000次,会占用很多内容空间
如果你传递指针进去…你函数调用你的那一个地方的数据,你调用1000次,只不过每一次用了8字节/16字节呃指针罢了,然后大家都指向那一个地方的数据…大大节省了空间
7-1关于嵌套结构体的应用
我们来看看这2个结构体
struct Person { //姓名 string Name; //性别 int Sex; //年龄 int Age; //电话 string Phone; //地址 string Location; }; //通讯录结构体 struct Boook { //联系人-数组 people P_arr[max]; //输入有多少个人 int index; };这是通讯里相关结构体
通讯录Book是一个类型集合
它包含了另外及一个结构体Peoson的数组与一个index的索引
Person结构体又包含了一些联系人的属性引用 int &=xx
指向indx就Book.index
指向Person就Book.Person[i].Age
如果用指针的话
好比把Book给指针化了
传参的时候&Book
然后访问的话
访问index就Book->index
访问sex就Book->Person[i].sex
如果访问index对应的sex就Book->Person[Book->index].sex其实–>给变量起别名
1-1导入部分
语法
数据类型- &-now_name = old_name
-----int ------&-now_var—=-old_var;上代码
#include#include using namespace std; int main() { int old=10; int &now=old; cout<<"old is "< 可以看出,
2个变量都访问了同一个值
更改其中一个变量其实等同于更改对应的all变量
1-2注意事项
引用时必须被初始化
int &now;(错误) int &new=old;(正确)引用不可以更改指向,就是引用指向了A,就不能再次指向B
int& now=pre; now=var_Mg;(这是一个个赋值 *** 作,正确) &now=var_Mg;(这是在修改引用的对象,错误)
2-1引用做函数的参数
以交换的函数为例子
- 值传递
- 指针传递
- 引用传递
引用传递
void swap(int& x,int& y) { int temp=0; temp=x; x=y; y=temp; } swap(a,b); 这里的传入参数 好比 int &x=a, int &y=b;
3-1引用做函数的返回值
代码#includeusing namespace std; //不能返回局部变量的引用 int& fun1() { int a=100; return a; } //可以返回全局区变量的引用 int& fun2() { static int b=200; return b; } int main() { //不能返回局部变量的引用 int& ret=fun1(); cout<<"第1次调用,本来是100,现在是 "< static int b=200;静态变量的生命周期要长一些,因此不会在栈里面,也不会被清空
fun2()=300;这里的fun1()的返回值是int&类型,所以的话,如果做左值,会改变引用的对象
4-1引用的本质
它的指向不可以修改,指向的单元数据却可以修改int& now=pre; 等同于 int *const now=⪯在调用引用时好比
now=1100; 等同于 *now=1000;
5-1常量引用
好比const int * const ptr;引用常量
const int & now=10; 等同于 int Buff=10; const int &now = temp;在函数中的常量引用
void fun(const int& now) { now=100;(编译器会报错,因为它不可修改) cout<<"valus is "<函数升级版
1-1函数的默认参数
我们可以对函数不传入参数,先前就给他一些默认的参数
如果我们要传入也可以…接受一定的顺序传入void fun(int a=10,intb=20,int c=30); 再调用的时候 fun(70,80); 那么的话,参数就会按着从前往后的顺序 a=70,b=80,c=30注意事项
- A.我们的默认参数的分布有一定的规则
- 默认参数都不去初始化
- 如果初始化其中一个,那么它后面的都要去初始化
- B.声明函数与定义函数只有其中之一可以去初始化
情况A
fun(int a.int b, int c)(正确) fun(int a=1,int b=2.int c=3)(正确) fun(int a,int b=1,int c=2)(正确) fun(int a=1,int b,int c)(错误)情况B
函数声明 void fun(int, int); 函数定义 void fun(int a,int b) { xxxxx; }于是在使用时
我们可以 void fun (int a=10,int b=10); void fun(int a,int b) { xxx; } 可以 void fun(int a,int b); void fun (int a=10,int b=10) { xxx; } //声明函数与定义函数只有其中之一可以去初始化,不可以都去初始化 void fun (int a=10,int b=10); void fun (int a=10,int b=10) { xxx; }
2-1函数的占位参数
就是你一定要给出一定的数据去占位置
好比你去图书馆,你可以不去图书馆,但是你要拿一本书去图书馆放着其实也没什么 void fun(int a, int , double = 20) { xxx; } 调用 fun(10,20,30); 这个,已知10,但20 ,30不一定用得上,但是必须要写上去占位置__
###3-1函数的重(chong)载(比较重要吧)吧
- 作用域
还比都在全局区域- 函数名称与类型一样same
- 函数的参数类型/参数个数/参数的顺序
代码示意void fun();//1 void fun(int a);//2 void fun (double a);//3 void fun (int a, double b);//4 void fun (double a,int b);//5 调用的话 fun()//调用第1个 fun(0)//调用第2个 fun(2.14)//调用第3个 fun(2,3.14)//调用第4个 fun(3.14,2)//调用第5给
3-2函数的重(chong)载的注意事项
//可读可写的选择 void fun ( int & x) void fun ( const int & x) fun(10); 上面你把常量10给传递进去,10是只读的常量,因此他会调用下面那个 void fun(int a=10,b=20) void fun(int a=10) fun(20); //这里存在一个歧义 //20上面下面都可以用 //对于于是要fun(10,20)才会调用上面面那个类
1-1导入部分
- 什么叫类?
有点像结构体,这个类就是你创建的类型- 什么叫成员?
成员就是你类里面的东西,保活成员属性+成员方法/行为- 什么叫成员属性?
好比一个人,它的身高,体重就是属性- 什么叫成员方法/行为?
好比你给一个人下命令,它动了,下命令的具体化就是一行为或者方法- 什么叫实例化?
好比你赋予一个人身高1.8米,体重80Kg,让他去参加国家篮球队打篮球,
这就叫实例化,其中身高1.8米,体重80Kg,叫成员属性初始哈,让他去参加国家篮球队打篮球,叫行为初始化
为什么说,有点结构体- 最后有个分号;
#include#include using namespace std; struct p { int age1; int age2; void set_a(int a) { age1=a; } void set_b(int b) { age2=b; } int get_age1() { return age1; } int get_age2() { return age2; } int sum() { return age1+age2; } }; int main() { p x; x.set_a(10); x.set_b(20); cout<<"x.get_age1()+x.get_age2()="< 于是你往后面看的话,其实发现于类有感觉差不多,后面也会说结构体与类的区别,也就是一个权限的区别
2-1访问权限
什么叫类外面/类里面?
class xx(类名) { ... }; 上面就是类的范围,也就是class的大括号囊括的部分代码示意
#include#include using namespace std; class student//定义了一个类,这就才生了一个范围 { //类头 public: string Name; int ID; void show() { cout<<"name "<
3-1struct与class的区别
是作用域的区别
然后的话,就应该没啥区别了
4-1成员属性设置为私有
其实这里面也没什么
就是一个访问的权限问题
也就是你不可直接访问,要绕一下才可以访问
可能这就有点像私有了吧
代码示意#include#include using namespace std; class Lover { public: //只可写 void re_set(string name ,int age) { Name=name; Age=age; } //只可读 void show() { cout<<"name: "< 小插曲
类在声明的时候不可以初始化
同样的,结构体在声明的时候也不可以初始化private: string Name="dqx"; int Age=100;上面就是错误的
做了一个实践的代码
这代码的话,值得注意的是
- 嵌套的类,一个类里面还有类.
c.get_center().get_x()
- 然后就是为什么会有类里的初始化与调用
你看c.get_center().get_x()这里的get就是`一个调用,如果你不去
int get_x() { return X; }请问你怎么流畅的获取,否者的话会比较麻烦
然后有兴趣的话,就看看下面的代码吧.... #include#include using namespace std; class point//随机点位的设计 { public: void set_x(int x)//设置x { X=x; } int get_x()//返回x { return X; } void set_y(int y)//设置y { Y=y; } int get_y()//返回y { return Y; } private: int X; int Y; }; class circle//本圆的半径与圆心 { public: void set_r(int r)//设置半径 { R=r; } int get_r()//设置半径 { return R; } void set_center(point center)//设置圆心 { Center=center; } point get_center()//返回圆心//让另外一个类作为这个类的成员 { return Center; } private: int R; point Center; }; void is_in_circle(circle &c,point &p) { //计算2点距离的平方 int distance= (c.get_center().get_x()-p.get_x())*(c.get_center().get_x()-p.get_x())+ (c.get_center().get_y()-p.get_y()*c.get_center().get_y()-p.get_y()); //计算半径的平方 int len_r=c.get_r()*c.get_r(); //判断 if(distance==len_r) cout<<"on the circle"< len_r) cout<<"out of circle"<
1-2-对象的初始化与清理
1-2-1-导入 构造函数 析构函数他不会去返回什么,就只是执行里面的东西罢了
代码示意
上面也就是说
构造函数可以重载
析构函数不可以重载#include#include using namespace std; //对象的初始化与清理 //1.构造函数,进行初始化 *** 作 class person { public: //1.构造函数 //没有返回值,不写void //函数名 与类的名称相同 //构造函数可以有参数,可以发生重载 //创建对象的时候,构造函数会主动调用,而其只会调用一次 person() { cout<<"构造函数"<
1-2-2构造函数的分类以及调用
大致框架#include#include using namespace std; class person { public: person() { cout<<"I am the 构造函数"< 无参数构造 #include#include using namespace std; //类的声明 class person { public: person() { cout<<"默认的构造函数,被调用了,人为修改了这里"< 有参数构造 #includeusing namespace std; #include //类的声明 class person { public: person(int x) { Age=x; cout<<"有参数构造,我被调用了"< 普通构造 只要不是拷贝就是普通构造
拷贝构造
上面得构造都是普通构造注意拷贝时要用const不可修改,并且以引用得形式访问
person(const person &BUff );
person p2(p1);#include#include using namespace std; class person { public: person(int x) { age=x; cout<<"我是有参数构造,被调用了"< 调用方式-括号法 #include#include using namespace std; class person { public: person() { cout<<"我是构造函数,被明摆着被调用了"< 调用方式-显示法 person nothing =person(20);
#include#include using namespace std; class person { public: person(int x) { age=x; cout<<"我是构造函数,被明摆着被调用了"< 调用的隐士法 #include#include using namespace std; class person { public: person(int x) { age=x; cout<<"构造函数"<
1-2-3-拷贝构造函数调用的时机
上面的情况简单的来说
- 你主动去拷贝,当然会有拷贝函数的调用
- 当你把实参作为参数传递给一个函数,这里会涉及拷贝函数
- 你把函数实参作为结果返回return给另外一个调用者,会涉及拷贝
#include#include using namespace std; class person { public: person() { cout<<"默认的打开,因为你在创建一个对象"< n"); fun1(); printf("n以函数的方式给函数参数传值-->n"); person p;//为什么析构一次呢??? fun2(p); printf("n以值的方式返回给局部对象-->n"); fun3(); cout<<"end"< 到底什么时候去调用函数值?
构造函数的调用规则
怎么理解这3句话?
1.如果一个函数你一个都不去人为的构造,系统就全部用它的那3个函数
2. 如果你自己构造了有参构造函数系统就只会提供拷贝函数与析构函数
3. 如果你自己构造了拷贝函数,系统就只会提供析构函数,其它声明有参构造,无参构造,它都不会去提供
所以你如果你构造了一个函数,那么意味着其它的函数很大可能你都要构造#include#include using namespace std; class person { public: int age; }; void fun() { person dqx; } int main() { fun(); system("pause"); } //系统自己用默默用它自己的3个函数 自己构造有参函数
#include#include using namespace std; class person { public: person(int x) { age=x; cout<<"我是有参数的构造函数,被明摆着被调用了"< 自己构造拷贝函数
#include#include using namespace std; class person { public: person(int x) { age=x; cout<<"我是有参数的构造函数,被明摆着被调用了"< 深度拷贝与浅拷贝 所谓的浅拷贝就是原封不动,一模一样的拷贝过去
- 它的问题在于不考虑细节
深拷贝会做一定的手脚
- 它的好处在于顾及到了细节
到底是什么细节?
浅拷贝
看后面吧#include#include using namespace std; class person { public: person(int x,string name) { Age=x; Name = new string (name);//我们如何去手动的释放 cout<<"我在这里开辟了一个堆区"< 引发异常
为什么会出现这个情况
其实析构函数的一个大用处在于~person()//它的关键用处在于堆区数据的释放 { delete Name;//如果本身为空,就不能再delete cout<<"我是析构函数,被明摆着调用了"<手动释放堆区,本来堆区的一些数据就是要程序员手动去释放的,于是这个析构函数就为程序员提供了一种方式
但是,这里开辟了2个对象,一个原样本,一个复制样本,因为是复制过去的,所以他们指向堆区的数据也都一样Name=BUff.Name;//这里就是一五一十的拷贝,直接把指向堆区的地址给拷贝过去,他们就指向了同一片堆区那么的话,delete Name的析构函数会指向2次,第一次把指向堆区的数据给delete,于是又来一个析构函数去delete堆区的数据,此刻原来堆区的数据已经被delete,那么再去delete就会引发异常
深度拷贝
问题解决?(也就是不要一五一十的拷贝,而是在里面添加几笔)
让拷贝时,数据不是指向堆区同一片的数据,而是拷贝到不同的区域
接下来上代码#include#include using namespace std; class person { public: person(int x,string name) { Age=x; Name = new string (name);//我们如何去手动的释放 cout<<"我在这里开辟了一个堆区"< 上面可以看见,他不是把地址给拷贝了过去,而是重新开辟了一个堆的数据
Name=new string(*BUff.Name);初始化列表给类赋初值格式
person xxx(int a,int b):A(a),B(b) { }代码
#include#include using namespace std; class person { public: person(int age,string name) :Age(age),Name(name) { } int Age; string Name; }; void fun() { person dqx(20,"dqx"); cout< 类对象作为类成员(嵌套式类) 还是类比函数一样…或者for的嵌套循环,.
这个例子结合了一下上面一节的初始化列表
上代码#include#include using namespace std; class PC { public: PC(string pc_name,string users_name,int pc_price):PC_Name(pc_name),Users_Name(users_name),PC_Price(pc_price) { } string PC_Name; string Users_Name; int PC_Price; }; class person { public: person(string name,string users_name,string pc_name,int price):Name(name),pc(pc_name,users_name,price) { } string Name; PC pc; }; void fun() { person dqx("dqx","XiaoMi","Re_lover",5000); cout< 静态成员犯的小错误
class{}没有加分号它的一个特性是共享吧…
- /静态的函数只能调用静态变量,为什么?
//因为静态变量与静态函数不会属于任何一个对象,
那么如果其中出现了一个非静态变量,而非静态变量又
必须要属于一个对象,静态与非静态混合在一起,共享与必须属于一个对象混合在一起,
就会发生矛盾,因为静态函数不知道
那个非静态的变量到底会属于谁谁,我们的静态函数也不知道/- //静态成员大家都可以用,所以不会属于任何一个对象
- //非静态的变量,只用创建一个对象后才能去使用
- //静态函数与变量也会又私有权限
- //静态变量的用法…类里声明…类外初始化
int lei::age1=0; int lei::age2=0; int lei::age4=0;代码示意图#include#include using namespace std; class lei { public: int age; static void fun1()//程序共享一个静态函数 { age1=18; age2=20; //age3=12; } //静态成员大家都可以用,所以不会属于任何一个对象 static int age1; static int age2; //非静态的变量,只用创建一个对象后才能去使用 int age3; private://静态函数与变量也会又私有权限 static void private_fun() { cout<<"你抓不到我的"< 成员变量与成员函数分开存储 在一个类里面
成员变量与成员函数的存储位置不一样
同时静态的成员又本来不属于类
所以计算sizeif()的时候,其实呢是算的非静态成员变量的大小
当类空的时候…
为了证明那个空类还存在过,计算机会分配一个字节给他意思意思一下,所以空类的大小是1Byte
代码示意图#include#include using namespace std; class lei1{}; class lei2 { public: int age1; static int age2; static void fun1(){} void fun2(){} int fun3(){} }; int lei2::age2=0; void fun2() { cout<<"空类占多少字节 ? "<
don’t look at me
C++一些高级的应用 暂停 pause#include清屏 cls... system("pause"); #include... system("cls"); 欢迎分享,转载请注明来源:内存溢出
评论列表(0条)