构造函数
类对象比普通变量复杂,并且由于类的封装性,不允许在类的非成员函数中直接访问类对象的私有和保护的数据成员,于是有专门用于对象初始化的成员函数:构造函数。
构造函数特点:
c++规定,每一个类必须有一个构造函数,无构造函数,就不能创建任何对象。
若未提供一个类的构造函数,则提供一个默认的构造函数,这是个无参构造函数,仅负责差UN国家爱你对象,而不作任何初始化工作
在用默认构造函数创建对象是,若创建的是全局对象或静态对象,全为0,否则是随机的。
class Point
{
int x=0;
int y={0};
public:
Point()=default; //生成默认的构造函数
};
类内初始化可以使用 = ,也可以使用 { },但不能使用()的初始化形式。
拷贝构造函数
- 使得对象可以按值传递 拷贝原始对象的值到传递给函数或函数返回的新对象中
- 编译器提供默认拷贝构造函数 拷贝对象每个每个数据成员到新对象中 (即: 逐个拷贝或赋值)
- 当数据成员包含指向动态内存的指针时同样存在严重问题
拷贝构造函数一般形式
类名(类名&对象名)
{
...};
三种情况相当于用一个已存在的对象去初始化新建立的对象, 此时, 调用拷贝构造函数:
① 使用一个已知对象初始化当前要创造的同类对象
② 函数以传值得方式将一个对象传入函数体
③ 函数的返回的是一个对象。
注意:
1.拷贝构造函数只是在用一个已存在的对象去初始化新建立的对象时调用,在对象进行赋值时,拷贝构造函数不被调用。
2.用一个常量初始化新建立的对象时,调用构造函数,不调用拷贝构造函数。
3.建立对象时,构造函数与拷贝构造函数有且仅有一个被调用。
深拷贝与浅拷贝
void main()
{
String s1("123456");
String s2=s1;
}
以上会出现错误:
原因:默认的拷贝构造函数实现的只能是浅拷贝,即直接将原对象的数据成员值依次拷贝给新对象中对应的数据成员,并没有为新对象另外分配内存资源。这样,如果对象的数据成员是指针,两个指针对象实际上指向的是同一块内存空间。
当类的数据成员中有指针类型时,我们就必须定义一个特定的拷贝构造函数,该拷贝构造函数不仅可以实现原对象和新对象之间数据成员的拷贝,而且可以为新的对象分配单独的内存资源,这就是深拷贝构造函数。
当执行String s2=s1时,默认的浅拷贝构造函数进行的是下列操作:
s2.len=s1.len;
s2.Str=s1.Str;
实际上是将s1.Str的地址赋给了s2.Str,并没有为s2.Str分配内存,执行String s2=s1;后,对象s2析构,释放内存,然后对象s1析构,由于s1.Str 和s2.Str所占用的是同一块内存,而同一块内存不可能释放两次,所以当对象s1析构时,程序出现异常,无法正常执行和结束。
复制构造函数声明与定义的要点:
1.其名称与类相同
2.仅带一个参数,类型与类相同,也就是与要初始化的对象相同
3.函数的参数传递方式是引用,所以参数类型是对象类型的引用。
class类名
{
public;
类名(形参列表) //构造函数
类名(const 类名&对象名) //复制构造函数声明
···
};
复制构造函数的定义:
类名::类名(const 类名&对象名) //复制构造函数的定义
{
···
};
const对象
- 声明对象不能被修改
const 成员函数
const 成员函数的声明和定义都需要用 const 修饰
构造函数和析构函数不能声明为 const
const 对象只能调用 const 成员函数
const 成员函数不能修改对象
原型:
ReturnType FunctionName(param1,param2…) const;
定义:
ReturnType FunctionName(param1,param2…) const { …}
int A::getValue() const
{
return privateDataMember;
}
int gethour() const;
void print() const;
int Time::gethour() const
//*const 在函数原型与函数实现中都需要得到体现*
{
....
}
- 常对象的声明方式:
const类名 对象名;
常对象的数据成员不能被改变,而且不能访问普通的函数成员
- 类的常函数成员的声明方式
返回类型 <类标识符::>函数名称(参数表) const:
1,const是函数声明的一部分,在函数的实现部分也需要加上const
2,const关键字可以重载函数名相同但是未加const关键字的函数
3,常成员函数不能用来更新类的成员变量,也不能调用类中未用const修饰的成员函数,只能调用常成员函数。即常成员函数不能更改类中的成员状态,这与const语义相符。
4,const 还能用来声明函数重载,当普通对象调用同名函数时,会选择最近的函数调用。
- 常数据成员的声明方式
const类型说明符 变量名;
常数据成员的初始化在构造函数的初始化列表中进行。
- 常引用的声明方式
const类型说明符 &变量名;
常引用也可做形参,常引用可以和常对象搭配,普通对象也可以和常引用搭配,在运行中,普通对象会被视为常对象。
成员初始化器
当类的私有成员均为非const类型,因此可以正常地调用构造函数进行初始化
如果该私有成员为const类型,则要求定义时就赋值,显然在类定义中直接赋值是错误的,而又不能像非const类型成员那样通过构造函数赋值语句来赋值
此时需要:成员初始化器
用途:
- 对特定类型的数据成员进行初始化:
const 数据成员 引用类型的数据成员 - 也可以用于任何数据成员
用法:
- 出现在构造函数参数列表后,函数体的左花括号前
- 用冒号 :与参数列表相分隔
- 数据成员名后跟括号,括号内包含初始值
- 多个数据成员用逗号分隔
- 初始化在构造函数执行前执行
public:
Circle(Point c,int r) : center(c),radius(r)
//使用c初始化了类的成员center,使用r初始化了类的成员radius
//radius 是半径
{}
Circle(int x=0;int y=0;int r=0)
:center(x,y),radius(r)
//(x,y)初始化了center的(x,y)