一、什么是构造函数?
构造函数是一个特殊的方法,它在类每次实例化创建对象的时侯自动调用,用于初始化对象。
构造函数的名字必须与类名完全相同,并且没有返回类型,甚至连void
也没有。
构造函数的目的是确保对象在创建时处于一个有效的、已知的状态。
二、构造函数存在的原因探讨:
1、假设我们要建一个Entity类,里面有位置信息,我们实例化后,打印出来,如下所示:
运行代码,打印出来一些随机值。
这是因为当我们实例化Entity类并且分配内存的时候,但实际上还没有对内存进行初始化,就是说内存空间还是原来的内容。
我们想做的可能就是初始化内存并把它设置为0,这样我们的位置默认就是0,而我们并不用显示的去指定一个值。
2、如果我们想手动打印X和Y,因为它们是公有的,所以我可以使用e.X直接把X打印出来。如下:
这里出现了错误,说使用未初始化的内存e和未初始化的局部变量(uninitialized local variable)e的报错信息。
换句话说,这个代码都不能通过编译,因为我们在尝试使用未初始化的内存。
上一个print函数仍然可以通过编译。但是它并没有像我们期望的那样运行,当然这是因为它在打印X和Y时被设置成随机值。
3、归纳一下
我们已经知道要做的就是需要做某种初始化。我们需要某种在我们创建Entity实例的时候就会自动把X和Y设置为0的方法,除非我们想设置为特定的值。
可能你想做的就是创建一个初始化方法。因此我们来创建一个Init方法,它的工作就是设置X和Y的值为0.
现在我能做的就是当我创建Entity的时候,调用e.Init()。然后调用print()方法尝试进行打印。
但是这样我们添加了太多的代码,我们必须定义这个Init方法,然后每当我要创建一个Enity的时候我都必须要去调用Init函数,这代码非常冗余而且一点也不清爽。如果当我们创建Entity的时候能自动运行这个初始化方法就好了,每当你创建一个对象的时候它就会被调用。
三、构造函数的定义
1、默认构造函数:
没有参数的构造函数。如果类中没有定义任何构造函数,编译器会自动生成一个默认构造函数。如果定义了其他构造函数,编译器则不会自动生成默认构造函数。
class MyClass {
public:MyClass() {// 初始化代码}
};
在Java中,基本数据类型中,比如int和float类型会默认被初始化为0,但是c++中不是这样的,你必须手动初始化所有的基本类型,不然,它们就会被设置为之前留存在内存中的值,所以非常非常重要的是,不要忘记进行初始化。还是那样,我会在以后讲解更多关于初始化和正确初始化的策略和方法。
2、参数化构造函数:接受一个或多个参数的构造函数。
让我们来看看带参数的构造函数,我门可以写多个构造函数,但是要给他们提供不同的参数,这个我写同名方法是一样的。其实这叫函数重载,就是相同的函数名有不同的参数的不同版本函数,我把x和y作为参数添加到这里,然后把x和y赋值给X和Y。
#include <iostream>class Entity
{
public:float X,Y;//用来表示Entity的位置;Entity(){X = 0.0f;Y = 0.0f;}Entity(float x,float y){X = x;Y = y;}void Print()//把位置输出到控制台{std::cout << X <<"," << Y << std::endl;}};int main()
{Entity e(10.0f,5.0f);//创建Entity的实例,e.Print();//调用print函数,运行函数
}
运行结果如下:
3、拷贝构造函数:用于创建一个对象作为另一个同类型对象的副本。
拷贝构造函数接受一个同类型对象的常量引用作为参数。如果类中没有定义拷贝构造函数,编译器会自动生成一个默认的拷贝构造函数。
class MyClass {
private:int* data;
public:MyClass(const MyClass& other) {// 深度拷贝代码data = new int(*other.data);}
};
4、移动构造函数(C++11及以后):用于“窃取”另一个对象的资源而不是复制它们,以提高效率。
移动构造函数接受一个同类型对象的右值引用作为参数。
class MyClass {
private:int* data;
public:MyClass(MyClass&& other) noexcept {data = other.data;other.data = nullptr; // 防止析构时释放资源}
};
四、注意事项
构造函数不会在你没有实例化对象的时候运行,所以如果你只是使用类的静态方法,构造函数是不会执行的。当你用new关键字创建对象实例的时候也会调用构造函数。
也有一些方法可以删除构造函数,比如说你有一个只有静态方法的Log类,就像这里的static void Log()。
我想让别人只像这样使用这个Log类,不希望别人创建实例。有两种不同的解决方法,我们可以通过设置private来隐藏构造函数。
运行你会发现,报错了,因为我不能访问构造函数。
如果不添加
private:
Log()
{
}
你可以看到显然是允许构造函数构造这个对象的。
因为c++默认给我们提供了构造函数。但是我们可以对编译器说:“不,我不想要那个默认的构造函数”
这里,我们就无法调用,因为默认构造函数已经不存在了,被删除了。
还有一些特殊类型的构造函数,比如说赋值构造函数和移动构造函数。他们都比较复杂,需要单独介绍。
构造函数是一个特殊的函数,会在你每次实例化类的时候调用,最主要的用处就是来初始化类
。当你创建一个对象实例的时候,确保你初始化了所有的内存和做了所有你需要的设置。