四类默认函数
C++作为面向对象编程的一门语言,与C语言的最大区别在于有了类的概念。类的概念脱胎于C语言中的结构体,但是他的范围更大,里面不光有变量、函数,而且还给变量、函数进行分类,分成私有(private)、共有(public)、保护(protect)。而在共有变量中,就存在这四个函数,他们为类的提供了基础和便利。
本博客从一个非常简单的类入手,讲解这四类函数的具体功能。
class test
{
public:
private:
int data;
};
构造函数
构造函数的编写
构造函数的本质就是将类实例化,生成具体的对象,代码为:
class test
{
public:
test(int a = 0)
{
data = a;
}
private:
int data;
};
构造函数十分直接,不需要返回值,函数名和类同名,创建时由编译器自动调动,目的就是给创建出来的新的对象赋上初值,一个对象一生中只调动一次。有趣的是,他是可以重载的。它可以传递各种类型的参数。例如:
class test
{
public:
//默认的构造函数,啥都没有
test()
{
;
}
//没有参数的构造函数
//无参构造函数
test()
{
data = 0;
}
//一个输入参数的构造函数
//全缺省构造函数
test(int a = 0)
{
data = a;
}
//两个输入参数的构造函数
//全缺省构造函数
test(int a = 0, int b = 0)
{
data = a + b;
}
private:
int data;
};
构造函数的使用
int main()
{
test t2(1, 2);
test t1();
return 0;
}
此时,一个叫t2的对象就生成了。其中需要注意的是,当你一旦写下了构造函数,系统默认的构造函数就不在生成了。
析构函数
析构函数是和构造函数相对应生成的,一个对象生成并完成了它的使命后,需要有一个函数来结束它的生命,这个函数就是析构函数。它的功能是完成类的一些资源清理工作。
析构函数的写法也非常有特点,他的函数名是类的名字前加上字符~,它无参数也无返回值,一个类中只能有一个析构函数。
析构函数的编写
它的代码如下:
//析构函数
~test()
{
;
}
就目前而言,析构函数一点用途都没有,因为没有什么值得他去析构的,但是==如果这其中涉及到了空间的开辟,那它的作用就非常大了。==比如:
class string
{
public:
string()
{
str = (int *)malloc(sizeof(int) * 5);
for (int i = 0; i < 5; i++)
{
*(str + i) = i;
}
}
~string()
{
free(str);
}
private :
int * str;
};
此时析构函数可以很好的将对象结束时没能及时收回的内存进行回收,防止内存泄漏。
小结:
构造函数和析构函数的存在和malloc和free以及new和delete,它们是一对锁死的CP,就像这样:
拷贝构造函数
平时我们在电脑中经常使用拷贝操作,同样的,我们在代码中也可以针对类进行拷贝操作,拷贝构造函数就是帮我们干这个的。
该函数的目的很明确,它只需要传递一个参数,那就是它所拷贝的对象但是别看它的功能简单,但是有些很重要的点需要注意:
首先,为了防止在拷贝的过程中拷贝构造函数把拷贝的对象随意修改,防止:我只是想借你看看,结果你把我的对象里的成员随意修改的结局,必须要把传递来的参数前加入const修饰。
其次传递的时候必须要使用引用传参,否则会产生无穷递归调用。
综上所述,一个拷贝构造函数的写法如下:
//拷贝构造函数
test(const test& t)
{
data = t.data;
}
如果不采用引用传参的话,就会像下面这种情况,这里面的test t,类名加上变量名,这会直接调用构造函数生成一个对象,然后又会继续调用构造函数生成另一个对象,子子孙孙无穷尽。
//错误的拷贝构造函数
test(const test t)
{
data = t.data;
}
还有一个需要注意的点:==拷贝构造函数
赋值重载函数
C++相对于C语言有另一个很有意思的点,它不仅可以重载函数,更可以重载操作符,比如我不想让加号实现相加的功能,我把它变成相乘也是可以的,只要你愿意,你在类中任意重载你想要的操作符。只需要定义operator加上想要重载的运算符即可。
赋值重载函数就是在这一大背景下应运而生的。它的目的也很简单,就是要实现:a = b
,这么一个简单的操作,只不过这里的a和b都是定义的对象,而不是常见的数。
它的具体代码如下:
//赋值重载函数
test& operator=(const test& a)
{
if (this != &a)
{
data = a.data;
}
}
和拷贝构造函数一样,它的输入必须也为引用传参,也要用const保护,除此之外,还需要引用返回,其实不用引用返回也可以,但是它会生成一个临时全局变量,然后再把结果传给临时的全局变量,这样的效率更低,多使用了一次构造函数,不如引用返回的效率高。
提一嘴
除了这四个默认函数,其实还有两个比较高级的成员函数:一个是const修饰类的成员函数,另一个是取地址操作符重载。