目录
1.如果设计一个类时,没有显示声明定义构造函数,析构函数,赋值运算符,地址运算符,则系统自动生成
class Demo{
private :
int val;
};
int main(){
Demo obj;
Demo obj1(obj); //调用默认的复制(拷贝)构造函数(复制:在定义对象的时候)
ibj1=obj;
Demo *p=&obj;
Demo *q=new Demo; //创建一个新的对象
delet e q;
}
2,析构函数
1.析构函数
在一个对象的生命期将结束的时候,应该回收该对象所占有的资源,或是完成一些清理工作。
2,析构函数的形式
~类名(); -------->析构函数没有返回值,也没有参数,所以不能重载
3,析构函数是在对象被销毁时自动被调用,释放对象所占有的资源
4,析构函数还可以被用户手动调用(对程序长期运行的静态成员手动释放空间)
5,当显示调用析构函数时,相当于调用普通的成员函数
#include<cstdlib>
class Demo{
piblic:
Demo(){
cout <<"Demo()"<<endl;
}
~Demo(){
cout <<"~Demo()"<<endl;
}
}
int main(){
cout <<"1111111111111"<<endl;
{
Demo a;
a.~Demo(); //当显示调用析构函数时,相当于调用普通函数
}
cout <<"2222222222222222"<<endl;
Demo *p=new Demo;//调用构造函数
p->~Demo(); //手动调用析构函数
delete p;
Demo *q=(Demo *)malloc(sizeof(Demo));//不会调用析构函数
free(q);//不会调用析构函数
创建一个数组
#include<cassert>
//assert:当表达式是负数时(假)的时候程序结束
class Array:
public:
Array(int num=10){
assert(num>0);//当条件为假时退出程序
size=num;
arr=new int[size];
int i;
for(i=0;i<size;i++)
{
arr[i]=i+1;
}
~Array(){
cout<<"~Array()"<<endl;
delete [] arr;
}
void getArray(){
int i;
for(i=0;i<size;i++)
cout <<arr[i]<<" ";
cout <<''\n';
}
private:
//分配一个size空间,把地址放在arr里面
int *arr;
int size;
};
int main()
{
Array obj;
obj.getArray();
Array obj1(20);//调用构造函数
obj1.geiArray();
//调用复制运算符
//构造函数生成了一片空间,调用复制会自动生成一片空间,obj2=obj;所以构造函数和复制构造函数同时指向一片空间,所以arr 一样,所以会造成double free
Array obj2=obj;//error 生成2个对象,会销毁,会double free
obj2.getArray();
}
3,new和malloc区别
Demo *p=new Demo;//调用构造函数
delete p;//调用析构函数
Demo *q=(Demo *)malloc(sizeof(Demo));//不会调用构造函数
free(q);//不会调用析构函数
复制构造函数的命名方式
Integer::Integert(const Integer &obj);
Integer obj1=obj;//复制构造函数
Integer obj1(obj);
obj1=obj;
注意:当类中没有手动添加复制构造函数,则会在类中生成一个复制构造函数,该自动构造函数会把obj中的成员变量依次付给iobj1
内存管理
- C/C++中定义了四个内存区间:
- 代码区、全局变量与静态变量区,局部变量区即栈区,动态存储区,即堆区。
- 静态存储分配
-
通常定义变量,编译器在编译时都可以根据该变量的类型知道所需要的内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间。
-
在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内容容量有限。
- 动态存储分配
4,深拷贝和浅拷贝
浅拷贝:构造函数生成了一片空间,调用复制会自动生成一片空间,obj1=obj;所以构造函数和复制构造函数指向同一片空间,所以arr一样,double free
深拷贝:所以要在复制构造函数obj中在开辟一段空间
5,this 指针
this指针是一个特殊的指针,指向类对象自身的首地址
每个类对象的成员函数都是一个this指针,指向调用的对象,如果要引用整个对象则*this
this指针仅在类内使用
class integer{
public:
integer(int num=o){
this->val=num;
}
void setval(int num=10){
this->val=num;
}
int getval(){
int val;
}
integer getinteger(){
return (*ths);
}
private:
int val;
};
int main()
{
integer obj(100);
cout<<obj.getval()<<endl;
integer obj1;
obj1=obj.getInteger();
cout <<obj1.getVal()<<endl;
}
6,static成员
静态成员可以将类的成员声明成静态的(static修饰)
静态成员不与具体的对象关联也不能直接访问类的其他成员
里面没有this指针
把一个类的成员说明为static,这个类无论有多少个对象被创建,这些对象共享static成员
static使用之前必须要定义
通过类名和作用域解析运算符来调用静态成员
类名::静态成员名称
对象.静态成员
count:所有对象共享
类中计算有多少个对象 创建对象+1,销毁对象-1
静态成员函数
静态成员里面没有thiszhizh
静态成员函数不能访问非静态成员,可以访问静态成员
static int count;
int val;
int Integer::count=0;
static int getCount(){
//return this->val;//静态成员没有this指针
//return val;//静态成员函数不能访问非静态成员
return count;
}
7,const
1,成员函数
当某个成员函数不会修改类中的成员,就可以把这个函数设置为const成员函数
一般形式:返回值 成员函数名 () const{
函数体;
}
const成员函数的 声明和定义都需要加上const
const成员函数不能修改对象
const成员函数不能调用非const 成员函数,可以调用const成员函数
非const成员函数可以调用const 成员函数
2,const对象
当对象中所有的成员都不需要修改时,就可以用const修饰,避免不小心修改里面的成员
一般形式
const 类 对象;
类 const 对象;
常对象只能访问常成员函数,不能访问非常成员函数
也就是说常对象只有析构函数域常成员函数才有意义
3,const成员变量
必须要初始化,且在构造函数的初始化列表中进行
非const成员函数可以使用const成员变量,但不能修改