目录
拷贝构造函数
- 拷贝构造函数是一种特殊的构造函数,当定义一个新对象并用一个同类型的对象对它进行初始化时,将显示使用拷贝构造函数。
- 当该类型的对象传递给函数或从函数返回该类型的对象时,将隐式调用拷贝构造函数。
- 在类中没有定义拷贝构造函数,编译器会自行定义一个。
- 拷贝构造函数一般为共有的。
- 如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。
- 有且仅有一个参数,并且是同类已知对象的常引用。至于为什么是对象引用,那是因为如果不是的话会导致无限递归。
常见形式
Goust(const Goust &g)
{
...............
}
必须定义的情况
有的类有一个数据成员是指针
必须被定义的原因
为啥子含有指针成员且需要对其进行分配时必须要有总定义拷贝构造函数存在呢,原因如下——
在这里先讲一下浅拷贝和深拷贝:
默认的拷贝构造函数实现的是浅拷贝,即直接将原对象的数据成员值依次复制给新对象中对应的数据成员,并没有为新对象另外分配内存资源。
浅拷贝示例代码如下:
#include<iostream>
using namespace std;
class Goust
{
public:
int b;
Goust(int c);
};
Goust::Goust(int c)
{
b=c;
}
void tran()
{
Goust o(10);
cout<<o.b<<endl;
Goust u(o);
cout<<u.b<<endl;
}
int main()
{
tran();
return 0;
}
输出
在实现原对象和新对象之间数据成员的拷贝的基础上,为新的对象分配单独的内存资源,这就是深拷贝构造函数。
深拷贝代码如下:
#include<iostream>
#include<cstring>
using namespace std;
class Goust
{
public:
char *a;
int b;
Goust(int c,char *p);
~Goust();
Goust(const Goust &g) ;
};
Goust::Goust(int c,char *p)
{
b=c;
a=new char[sizeof(p)];
strcpy(a,p);
}
Goust::~Goust()
{
if(a!=NULL)
{
delete a;
a=NULL;
}
}
Goust::Goust(const Goust &g)
{
b=g.b;
a=new char[sizeof(g.a)];
strcpy(a,g.a);
}
void tran()
{
char p[]="happy";
Goust o(10,p);
cout<<o.b<<endl;
cout<<o.a<<endl;
Goust u(o);
cout<<u.b<<endl;
cout<<u.a<<endl;
}
int main()
{
tran();
return 0;
}
输出
当数据成员中含有指针时,使用浅指针会使两个类中的两个指针指在一起,当对象快结束的时候,会有两次析构函数被调用,从而致使指针悬挂现象。深拷贝会在堆内存中另外申请空间,因此解决了空间悬挂。
使用 情境
1、一个对象以值传递的方式传入函数体
2、一个对象以值传递的方式从函数返回
#include<iostream>
using namespace std;
class Test
{
private:
int a;
public:
Test(int x = 0) : a(x)
{
cout << "construction" << endl;
}
Test(const Test & obj)
{
cout << "Copy construction" << endl;
a = obj.a;
}
};
Test Fun(Test t)
{
return t;
}
void main()
{
Test t1; // 调用构造函数
Test t2(t1); // 调用拷贝构造函数
Fun(t2); // 两次调用拷贝构造函数
system("pause");
}
3、一个对象需要通过另外一个对象进行初始化。
#include<iostream>
using namespace std;
class Test
{
private:
int a;
public:
Test(int x = 0) : a(x)
{
cout << "construction" << endl;
}
Test(const Test & t)
{
cout << "Copy construction" << endl;
a = t.a;
}
};
void main()
{
Test t1; // 调用构造函数
Test t2(t1); // 调用拷贝构造函数
Test t3 = t2; // 调用拷贝构造函数
system("pause");
}
assert
在这里插入一个函数,断言assert(),可用于检测,若括号内为假,停止程序运行,若为真,则进行。其括号内只能有一个条件。
使用 assert 的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。
在调试结束后,可以通过在包含 #include 的语句之前插入 #define NDEBUG 来禁用 assert 调用,示例代码如下:
#include
#define NDEBUG
#include
内联函数
- 是通常与类一起使用,在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符。
- 当函数只有 10 行甚至更少时才将其定义为内联函数.
- 如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义。如果已定义的函数多于一行,编译器会忽略 inline 限定符。
- 如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。
- 在内联函数内不允许使用循环语句和开关语句。
- 虚函数和递归函数就不会被正常内联。
- 内联函数的优点或者说是引入的意义就在于使代码更加高效。