C++面向对象之构造函数
定义
构造函数也叫构造器,在对象创建的时候自动调用,一般用于完成对象的初始化工作
下方示例中Person()就是类的构造函数
class Person
{
public:
Person();//创建类时自动创建的构造函数,也可以手动添加,这个为构造函数的声明
~Person();//虚构函数,后续文章会记录
int m_member;
private:
};
Person::Person()//构造函数的实现-无参数构造函数
{
cout << "创建了对象,构造函数自动执行" << endl;
//构造函数里可以做一下成员变量的初始化工作,因为对象创建成功,构造函数就直接调用,比如:
m_member = 5;
}
int main()
{
Person person1;//创建了这个对象的时候,构造函数就直接自动调用了
cout << person1.m_member << endl;//打印为5
getchar();
return 0;
}
构造函数的用途
就记住一个最大的用途,就是初始化类中的成员变量(这与python中的def _ init _()函数一样)
使用构造函数有几点需要注意
- 新建类的时候,像VS这种IDE会给你自动添加构造函数,包括类中的构造函数声明,实现中的构造函数实现。
- 构造函数名与类同名,无返回值(void都不可以写),可以有参数,可以重载,可以有多个构造函数
- 一旦自定义了构造函数,必须用自定义的构造函数来创建初始化对象。这也就意味着如果类中有自己写的构造函数,然后你没有与之对应的对象示例化,就会报错
class Person
{
public:
Person(int a,int b);//创建类时自动创建的构造函数,也可以手动添加,这个为构造函数的声明
int m_member;
int m_value;
private:
};
Person::Person(int a,int b)//构造函数的实现-有参数构造函数
{
m_member = a;
m_value = b;
}
int main()
{
Person person1;//只这么创建对象,会报错,因为和仅仅独存的构造函数对应不上
Person person2(10,20);//必须这么创建对象,得和构造函数对应上
getchar();
return 0;
}
- 但如果有多个构造函数,就可以实现构造函数的重载
class Person
{
public:
Person(int a,int b);//创建类时自动创建的构造函数,也可以手动添加,这个为构造函数的声明
Person();
int m_member;
int m_value;
private:
};
Person::Person(int a,int b)//构造函数的实现-有参数构造函数
{
m_member = a;
m_value = b;
}
Person::Person()//构造函数的实现-有参数构造函数
{
m_member = 0;
m_value = 0;
}
int main()
{
Person person1;//只这么创建对象,就不会报错,因为有与之对应的构造函数
Person person2(10,20);//必须这么创建对象,得和构造函数对应上
getchar();
return 0;
}
- 如果类中没写构造函数,必须采用Person person这样的方式创建对象,不可以Person person(10)这种创建对象
class Person
{
public:
int m_member;
int m_value;
private:
};
int main()
{
Person person1;//由于类中没有声明构造函数,所以必须这么创建对象
Person person2(10);//没有与之对应的构造函数,这样创建对象是错的
getchar();
return 0;
}
- 通过malloc创建的对象不会调用构造函数,但通过new创建的对象会调用构造函数。同样是堆空间开辟内存,但是调用构造函数与否却有差别。
new对比malloc,同样都是申请堆空间内存,但是比malloc多做了一个事情就是调用构造函数
class Person
{
public:
int m_member;
int m_value;
private:
};
int main()
{
Person *p_malloc = (Person *)malloc(sizeof(Person));//不会调用构造函数
free(p_malloc);//防止内存泄漏
Person *p_new = new Person;//会调用构造函数
delete p_new;//防止内存泄漏
}
malloc只申请堆空间,不可以调用构造函数,即,不可以直接初始化成员变量,想要初始化就必须调用memset函数
new既可以申请堆空间,又可以调用构造函数达到初始化成员变量的目的,还可以直接初始化成员变量:Person *p = new Person(0)*
C++中想要把对象放在堆空间,尽量用new,别用malloc,因为new才会调用构造函数,才会初始化一些成员变量。
调用构造函数的不同情况
下面三种创建对象的方法,都会调用哪个构造函数呢?
class Person
{
public:
Person();//创建类时自动创建的构造函数,也可以手动添加,这个为构造函数的声明
Person(int value);//与默认的构造函数形成重载
private:
};
Person::Person()//构造函数的实现-无参数构造函数
{
cout << "无参构造函数的调用" << endl;
}
Person::Person(int value)//构造函数的实现-有参数构造函数
{
cout << "有参构造函数的调用" << endl;
}
int main()
{
//这三个会自动调用哪个构造函数呢?
Person f_person0;//会调用无参的Person::Person()
Person f_person1();//这其实是个函数声明,只不过返回值是Person类型的
Person f_person2(10);//会调用有参的Person::Person(int parm)
//这三个会自动调用哪个构造函数呢?
Person *p0 = new Person;//会调用无参的Person::Person()
Person *p1 = new Person();//会调用无参的Person::Person(),如果是new int()代表这四个字节初始化为0,但是new 类 不是这样的
Person *p2 = new Person(10);//会调用有参的Person::Person(int value),//注意这样里面写成10,不代表将Person下的成员变量全部初始化为10,
//因为这个10其实是实参,但如果没有定义构造函数,这个10就是默认全部初始化为10了
getchar();
return 0;
}
括号里没有参数:new int()和new Class()是不一样的。
new int()代表的是初始化内存空间都为0
new Person()表示的是会调用无参的构造函数
括号里有参数:new int(10)和new Person(10)是不一样的。
new int(10)代表的是初始化内存空间都为10,这个10是放在这块内存的数值
new Person(10)表示的是会调用有参的构造函数,这个10是实参
关于构造函数的一个广为流传的错误:
错误原话:默认情况下,编译器会为每一个类生成空的、无参的构造函数,即Person(); 这句话在C++里是错的,不严谨。
严谨表达:如果你在类中定义成员变量时,对成员变量进行赋值操作了,那么编译器就会为你默认生成空的、无参的构造函数,即Person()。反过来,如果没有对变量进行初始化操作,就不会生成空的、无参构造函数。
class Person
{
public:
int m_member;//如果类中这么定义变量,创建对象时,编译器就不会为这个类创建空的无参的构造函数
int m_member=0;//如果类中这么定义变量,创建对象时,编译器就会为这个类创建空的无参的构造函数
private:
};
成员变量初始化问题
无自定义构造函数情况下,成员变量初始化问题
即我不写构造函数,然后分别在全局区、栈空间、堆空间创建对象,看看哪个内存区间的对象默认初始化成员变量
class Person
{
public:
int m_age;
private:
int m_height;
};
//全局区,
Person g_person; //初始化了成员变量为0
int main()
{
//栈空间
Person person;//没有初始化
//堆空间
Person *p0 = new Person;//没有初始化
Person *p1 = new Person();//初始化了成员变量为0,
cout << g_person.m_age << endl;//0,说明初始化了成员变量为0
cout << person.m_age << endl;//报错 “使用了未初始化的局部变量“person” 说明没有初始化成员变量
cout << p0->m_age << endl;//-85818896185,说明没有初始化成员变量,随机赋值了
cout << p1->m_age << endl;//0,说明初始化了成员变量为0
getchar();
return 0;
}
- 初始化在全局区的对象,会默认初始化成员变量为0
- 初始化在栈空间的对象,不会初始化成员变量
- 初始化在堆空间的对象,类名后加括号的会默认初始化成员变量为0,不加括号的不会初始化成员变量
定义构造函数情况下,但构造函数里无实现,此时成员变量初始化问题
如果我声明了构造函数,但是没有实现,即,函数没有函数体,Person *p1 = new Person();这样就不会初始化成员变量了,因为它自动调用了没有实现的构造函数
class Person
{
public:
int m_age;
Person(){
//无实现
}
private:
int m_height;
};
int main()
{
//堆空间
Person *p0 = new Person;//没有初始化
Person *p1 = new Person();//这样也没有初始化
cout << p0->m_age << endl;//-85818896185,说明没有初始化成员变量,随机赋值了
cout << p1->m_age << endl;//-85818896185,说明没有初始化成员变量,随机赋值了
getchar();
return 0;
}
总结初始化成员变量的问题
所以,总结一下初始化变量的问题
- 如果没有定义构造函数,栈空间和堆空间的一种情况是不会初始化成员变量的,就是Person不带括号的情况;
- 全局区定义的变量,都默认初始化为0,无论是对象、变量…
- 如果自定义了构造函数,除了全局区,其他内存空间的成员变量默认都不会初始化,除非你手动在构造函数里初始化