-
如果没有提供构造/析构函数,编译器将提供空实现的构造/析构函数。
-
如果提供了构造/析构函数,编译器将不提供空实现的构造/析构函数。
-
创建对象的时候,如果重载了构造函数,编译器根据实参匹配相应的构造函数。没有参数的构造函数也叫默认构造函数。
-
创建对象的时候不要在对象名后面加空的圆括号,编译器误认为是声明函数。(如果没有构造函数、构造函数没有参数、构造函数的参数都有默认参数)
-
在构造函数名后面加括号和参数不是调用构造函数,是创建匿名对象。
-
接受一个参数的构造函数允许使用赋值语法将对象初始化为一个值(可能会导致问题,不推荐)
CGirl girl =10;
-
本质的区别:
CGirl girl = CGirl("西施"20); // 显式创建对象。
CGirl girl; // 创建对象。
girl = CGirl("西施"20); // 创建匿名对象,然后给现有的对象赋值。
- 用
new/delete
创建/销毁对象时,也会调用构造/析构函数。. - 不建议在构造/析构函数中写太多的代码,可以调用成员函数
- 除了初始化,不建议让构造函数做太多工作(只能成功不会失败)。
- C++11支持使用统一初始化列表
- 如果类的成员也是类,创建对象的时候先构造成员类,销毁对象的时候先析构成员类。
CGirl girl = {"西施"20};
CGirl girl {"西施"20};
CGirl* girl = new CGirl{ "西施"20 };
5的例子
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class CGirl // 超女类CGirl。
{
public:
string m_name; // 姓名属性。
int m_age; // 年龄属性。
char m_memo[301]; // 备注。
CGirl() // 没有参数的构造函数。
{
m_name.clear(); m_age = 0; memset(m_memo, 0, sizeof(m_memo));
cout << "调用了CGirl()构造函数。\n";
}
CGirl(string name) // 一个参数(姓名)的构造函数。
{
CGirl(); //没有调用构造函数,而是创建了匿名对象(创建后马上被销毁了)
cout << "调用了CGirl(name)构造函数。\n";
m_name = name;
}
CGirl(int age) // 一个参数(年龄)的构造函数。
{
CGirl(); //没有调用构造函数,而是创建了匿名对象(创建后马上被销毁了)
cout << "调用了CGirl(age)构造函数。\n";
m_age = age;
}
CGirl(string name, int age) // 两个参数的构造函数。
{
CGirl(); //没有调用构造函数,而是创建了匿名对象(创建后马上被销毁了)
cout << "调用了CGirl(name,age)构造函数。\n";
m_name = name; m_age = age;
}
CGirl(string name, int age ,char memo[301]) // 两个参数的构造函数。
{
CGirl(); //没有调用构造函数,而是创建了匿名对象(创建后马上被销毁了)
cout << "调用了CGirl(name,age)构造函数。\n";
m_name = name; m_age = age;
strcpy(m_memo,memo);
}
// void initdata()
// {
// m_name.clear(); m_age = 0; memset(m_memo, 0, sizeof(m_memo));
// }
~CGirl() // 析构函数。
{
cout << "调用了~CGirl()\n";
}
void show() // 超女自我介绍的方法。
{ cout << "姓名:" << m_name << ",年龄:" << m_age << ",备注:" << m_memo<< endl; }
};
int main()
{
//CGirl girl();
CGirl girl("西施");
//CGirl girl("西施",8); // 创建超女对象,为成员姓名和年龄设置初始值。
girl.show(); // 显示超女的自我介绍。
}
构造函数
在创建对象时,自动的进行初始化工作。(例如初始化变量的代码)
访问权限必须是public。
函数名必须与类名相同。
没有返回值,不写void。
可以有参数,可以重载,可以有默认参数。
创建对象时只会自动调用一次,不能手工调用。
析构函数
在销毁对象前,自动的完成清理工作。(例如释放内存的代码)
访问权限必须是public。
函数名必须在类名前加~。
没有返回值,也不写void。
没有参数,不能重载。
销毁对象前只会自动调用一次,但是可以手工调用。
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class CGirl // 超女类CGirl。
{
public:
string m_name; // 姓名属性。
int m_age; // 年龄属性。
char m_memo[301]; // 备注。
CGirl() // 没有参数的构造函数。
{
initdata();
cout << "调用了CGirl()构造函数。\n";
}
CGirl(string name) // 一个参数(姓名)的构造函数。
{
initdata();
cout << "调用了CGirl(name)构造函数。\n";
m_name = name;
}
CGirl(int age) // 一个参数(年龄)的构造函数。
{
initdata();
cout << "调用了CGirl(age)构造函数。\n";
m_age = age;
}
CGirl(string name, int age) // 两个参数的构造函数。
{
initdata();
cout << "调用了CGirl(name,age)构造函数。\n";
m_name = name; m_age = age;
}
void initdata()
{
m_name.clear(); m_age = 0; memset(m_memo, 0, sizeof(m_memo));
}
~CGirl() // 析构函数。
{
cout << "调用了~CGirl()\n";
}
void show() // 超女自我介绍的方法。
{ cout << "姓名:" << m_name << ",年龄:" << m_age << ",备注:" << m_memo<< endl; }
};
int main()
{
// CGirl girl; // 创建超女对象,不设置任何初始值。
// CGirl girl("西施"); // 创建超女对象,为成员姓名设置初始值。
// CGirl girl("西施",8); // 创建超女对象,为成员姓名和年龄设置初始值。
//CGirl girl=CGirl(); // 创建超女对象,不设置任何初始值。
// CGirl girl=CGirl("西施"); // 创建超女对象,为成员姓名设置初始值。
// CGirl girl=CGirl("西施",8); // 创建超女对象,为成员姓名和年龄设置初始值。
//CGirl girl = 8; // 使用赋值语法初始化对象。
// CGirl *girl=new CGirl; // 创建超女对象,不设置任何初始值。
// CGirl *girl=new CGirl("西施"); // 创建超女对象,为成员姓名设置初始值。
CGirl *girl=new CGirl("西施",8); // 创建超女对象,为成员姓名和年龄设置初始值。
girl->show(); // 显示超女的自我介绍。
delete girl;
}
拷贝构造函数
用一个已存在的对象创建新的对象,不会调用(普通)构造函数,而是调用拷贝构造函数。
如果类中没有定义拷贝构造函数,编译器将提供一个拷贝构造函数,它的功能是把已存在对象的成员变量赋值给新对象的成员变量。
用一个已存在的对象创建新的对象语法:
类名 新对象名(已存在的对象名);
类名 新对象名=已存在的对象名;
拷贝构造函数的语法:
类名(const 类名& 对象名){......}
- 访问权限必须是public。
- 函数名必须与类名相同。
- 没有返回值,不写void。
- 如果类中定义了拷贝构造函数,编译器将不提供默认的拷贝构造函数。
- 以值传递的方式调用函数时,如果实参为对象,会调用拷贝构造函数。
- 函数以值的方式返回对象时,可能会调用拷贝构造函数(VS会调用,Linux不会,g++编译器做了优化)。
- 拷贝构造函数可以重载,可以有默认参数。
类名(…,const 类名& 对象名,…){…} - 如果类中重载了拷贝构造函数却没有定义默认的拷贝构造函数,编译器也会提供默认的拷贝构造函数。
5的例子:
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class CGirl // 超女类CGirl。
{
public:
string m_name; // 姓名属性。
int m_age; // 年龄属性。
// 没有参数的普通构造函数。
CGirl() { m_name.clear(); m_age = 0; cout << "调用了CGirl()构造函数。\n"; }
//拷贝构造函数的功能是把已存在对象的成员变量赋值给新对象的成员变量。
// 没有重载的拷贝构造函数(默认拷贝构造函数)。
CGirl(const CGirl &gg) { m_name="漂亮的"+gg.m_name; m_age = gg.m_age-1; cout << "调用了CGirl(const CGirl &gg)拷贝构造函数。\n"; }
// 重载的拷贝构造函数。
CGirl(const CGirl& gg,int ii) { m_name = "漂亮的" + gg.m_name; m_age = gg.m_age - ii; cout << "调用了CGirl(const CGirl &gg,int ii)拷贝构造函数。\n"; }
// 析构函数。
~CGirl() { cout << "调用了~CGirl()\n"; }
// 超女自我介绍的方法,显示姓名和年龄。
void show() { cout << "姓名:" << m_name << ",年龄:" << m_age << endl; }
};
void func(CGirl g){
g.show();
}
int main()
{
CGirl g1;
g1.m_name = "西施"; g1.m_age = 23;
//用一个已存在的对象创建新的对象,
CGirl g2(g1,3);
g2.show();
cout<<"以值传递的方式调用函数时,如果实参为对象,会调用拷贝构造函数。"<<endl;
func(g1);
}
6的例子:
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class CGirl // 超女类CGirl。
{
public:
string m_name; // 姓名属性。
int m_age; // 年龄属性。
// 没有参数的普通构造函数。
CGirl() { m_name.clear(); m_age = 0; cout << "调用了CGirl()构造函数。\n"; }
//拷贝构造函数的功能是把已存在对象的成员变量赋值给新对象的成员变量。
// 没有重载的拷贝构造函数(默认拷贝构造函数)。
CGirl(const CGirl &gg) { m_name="漂亮的"+gg.m_name; m_age = gg.m_age-1; cout << "调用了CGirl(const CGirl &gg)拷贝构造函数。\n"; }
// 重载的拷贝构造函数。
CGirl(const CGirl& gg,int ii) { m_name = "漂亮的" + gg.m_name; m_age = gg.m_age - ii; cout << "调用了CGirl(const CGirl &gg,int ii)拷贝构造函数。\n"; }
// 析构函数。
~CGirl() { cout << "调用了~CGirl()\n"; }
// 超女自我介绍的方法,显示姓名和年龄。
void show() { cout << "姓名:" << m_name << ",年龄:" << m_age << endl; }
};
CGirl func(){
CGirl g;
g.m_name="西施";
g.m_age=22;
return g;
}
int main()
{
CGirl gg = func();
gg.show();
}
8的例子:
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class CGirl // 超女类CGirl。
{
public:
string m_name; // 姓名属性。
int m_age; // 年龄属性。
// 没有参数的普通构造函数。
CGirl() { m_name.clear(); m_age = 0; cout << "调用了CGirl()构造函数。\n"; }
//拷贝构造函数的功能是把已存在对象的成员变量赋值给新对象的成员变量。
// 没有重载的拷贝构造函数(默认拷贝构造函数)。
//CGirl(const CGirl &gg) { m_name="漂亮的"+gg.m_name; m_age = gg.m_age-1; cout << "调用了CGirl(const CGirl &gg)拷贝构造函数。\n"; }
// 重载的拷贝构造函数。
CGirl(const CGirl& gg,int ii) { m_name = "漂亮的" + gg.m_name; m_age = gg.m_age - ii; cout << "调用了CGirl(const CGirl &gg,int ii)拷贝构造函数。\n"; }
// 析构函数。
~CGirl() { cout << "调用了~CGirl()\n"; }
// 超女自我介绍的方法,显示姓名和年龄。
void show() { cout << "姓名:" << m_name << ",年龄:" << m_age << endl; }
};
int main()
{
CGirl gg;
gg.m_name="西施",gg.m_age=22;
//调用了系统提供的默认拷贝构造函数;
CGirl g2(gg);
g2.show();
}