0.拷贝构造函数
其实就是类与类之间的赋值操作所要调用的函数(因为类对象与普通对象不同,类对象内部结构较为复杂,存在各种成员变量)
代码举例:
#include<iostream>
using namespace std;
class Myclass {
private:
int a;
public:
Myclass(int b)
{ a = b;}
Myclass(const Myclass& C)
{
a = C.a;
}
void Show ()
{
cout<<a<<endl;
}
};
int main()
{
Myclass A(100);
Myclass B = A;
B.Show ();
return 0;
}
拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量。
1.深浅拷贝
浅拷贝
在对象赋值时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝
代码举例:
#include<iostream>
using namespace std;
class Array{
public:
Array(int t)
{
cout << "Array" << endl ;
count = t ;
}
Array(const Array &temp)
{
cout << "~Array" << endl ;
count = temp.count ;
}
void print()
{
cout << "count == " << count << endl;
}
private:
int count;
};
int main(void)
{
Array My1(5);
Array My2 = My1;
My1.print();
My2.print();
}
运行结果:
深拷贝
先来看下面的一个例子:
#include<iostream>
using namespace std;
class Array{
public:
Array(int t)
{
cout << "Array" << endl ;
count = t ;
p = new int[count];
for(int i= 0;i != count ;++i)
p[i] = i*i ;
}
Array(const Array &temp)
{
cout << "~Array" << endl ;
count = temp.count ;
p = new int[temp.count];
p = temp.p;
}
void print()
{
cout << "count == " << count << endl;
for(int i =0;i != count ;++i)
cout << p[i] << endl ;
}
void printAddr()
{
cout << "p == " << p << endl ;
}
~Array()
{
delete []p;
p= NULL;
}
private:
int count;
int *p ;
};
int main(void)
{
Array My1(5);
Array My2 = My1;
My1.printAddr();
My2.printAddr();
My1.print();
My2.print();
}
运行截图:
可以很明显的看到图中的报错“double free”。说明我们将一块内存 free了两次。产生了错乱!那么是什么原因引起的呐?
没错就是我们的拷贝构造函数,当我们写为p = temp.p; 就是将一个对象的p指针指向了传进来的temp.p的地址。那么他们两个对象的指针就指向了同一块内存,之后在析构函数中被free时,就会产生double free 。那么如何解决这个问题呐?
就是将传进来的temp 的每一块内存分别赋值给p,于是拷贝构造函数就成了这样:
Array(const Array &temp)
{
cout << "~Array" << endl ;
count = temp.count ;
p = new int[temp.count];
for(int i = 0 ;i< temp.count ;++i)
p[i] = temp.p[i];
}
运行结果:
没错,这就是我们的深拷贝啦~_~
2.对象成员指针
所谓的对象成员指针就是指在一个类的成员中出现了另一个类的指针。
代码举例:
#include<iostream>
using namespace std;
class coordinate {
public:
coordinate(int x,int y)
{
this->x= x;
this->y =y;
}
~coordinate()
{
}
int getX()
{
return x;
}
int getY()
{
return y;
}
private:
int x;
int y;
};
class Line{
public:
Line(int x1 ,int y1,int x2,int y2)
{
A = new coordinate(x1,y1);
B = new coordinate(x2,y2);
}
void print()
{
cout << A->getX() << " " << A->getY() << endl ;
cout << B->getX() << " " << B->getY() << endl ;
}
~Line()
{
delete A;
A=NULL;
delete B;
B=NULL;
}
private:
coordinate *A;
coordinate *B;
};
int main(void)
{
Line *p;
int *t;
p= new Line(1,2,3,4);
p->print();
delete p ;
p= NULL;
cout <<" t == " << sizeof(t)<< endl ;
cout <<" p == " << sizeof(p)<< endl ;
cout <<" sizeof(line1) == " << sizeof(Line)<< endl ;
return 0;
}
运行截图:
PS:不知道大家有木有注意到 sizeof 什么什么的那部分,在 64 位的机器中,一个指针占8个字节,那么请想上一想?为什么sizeof(line1)输出的是16呐?因为line对象中有两个指针coordinate 呀。哈哈哈
3.常对象成员与函数
常对象成员:就是用 const 来修饰的对象的数据成员对象,初始化时就只能用初始化列表来完成初始化。常成员函数就是用const来修饰成员函数,那么常成员函数中就不能修改数据成员的值了,因为:
void play() const
{
x= 10;
}
就等价于下面:
void play(const Myclass *this)
{
this->x = 10;
}
显然给一个 const指针指向的数据成员赋值自然是错误的。还有:
void play() const;
void play() ;
两个函数互为重载,但是这个只能说可以这样用,但绝对不会有人这样使用!!!!
如何调用常成员函数:
代码举例:
int main(void)
{
const Myclass Myclass(4);
}
PS:一般使用初始化列表就三种情况,
1.const成员的初始化
2.有参构造的对象成员
3.引用成员的初始化
4.常指针与常引用
就是下面的这两个东东:
const coordinate &My2 = My1;
const coordinate *p = &My1;
说明:与常对象相同,只能使用常成员函数,不能使用其他类型的函数
代码举例:
#include<iostream>
using namespace std;
class coordinate {
public:
coordinate(int x,int y)
{
this->x= x;
this->y =y;
}
~coordinate()
{
}
int getX()
{
}
int getX() const
{
return x;
}
int getY() const
{
return y;
}
void printInfo() const
{
cout << "liushengxi ----- " << endl;
}
private:
int x;
int y;
};
int main(void)
{
coordinate My1(1,2);
const coordinate &My2 = My1;
const coordinate *p = &My1;
My2.getX();
p->getY();
return 0;
}