cpp——类——构造函数

概述

为了类的使用方便,类的设计尽可能使类的使用方式与内置类型无区别,构造函数则是类模仿内置类型的初始化
内置类型初始化支持直接初始化,复制初始化,默认初始化,构造函数对应于内置类型的各种初始化:
  • 带参数构造函数——直接初始化
  • 复制构造函数——复制初始化
  • 默认构造函数——默认初始化
构造函数特点:
  • 函数名与类名同名,用来标记和识别构造函数
  • 没有返回值,构造函数是对自身的初始化,返回值无意义,因为没有返回值的接收者
  • 初始化行为,构造函数在生成(定义)对象时自动调用,因此构造函数只能执行一次,否则就多次初始化
构造函数组成:
  • 初始化列表和函数体
  • 初始化列表完成初始化行为,初始化列表确保类的所有数据成员都得到合适的初始化
  • 函数体与普通函数函数体无区别,函数体可进行一些深层定制,一般完成的都是一些简单功能

辅助类

class CAnimal
{
public:
    CAnimal() : mGroup(0)
    {
        cout << "CAnimal()" << endl;
    }
    
    CAnimal(int group) : mGroup(group)
    {
        cout << "CAnimal(" << group << ")" << endl;
    }
    
    CAnimal(const CAnimal &other) : mGroup(other.mGroup)
    {
        cout << "CAnimal(const CAnimal &other)" << endl;
    }
    
private:
    int mGroup;
};

class CDog : public CAnimal
{
public:
    CDog() : mLoyal(10)
    {
        cout << "CDog()" << endl;
    }
    
    CDog(int loyal) : CAnimal(1), mLoyal(loyal)
    {
        cout << "CDog(" << loyal << ")" << endl;
    }
    
    CDog(const CDog &other) : CAnimal(other), mLoyal(other.mLoyal)
    {
        cout << "CDog(const CDog &other)" << endl;
    }
    
private:
    int mLoyal;
};

class CCat : public CAnimal
{
public:
    CCat() : mCute(20)
    {
        cout << "CCat()" << endl;
    }
    
    CCat(int cute) : CAnimal(2), mCute(cute)
    {
        cout << "CCat(" << cute << ")" << endl;
    }
    
    CCat(const CCat &other) : CAnimal(other), mCute(other.mCute)
    {
        cout << "CCat(const CCat &other)" << endl;
    }
    
private:
    int mCute;
};

class CPig : public CAnimal
{
public:
    CPig() : mWeight(30)
    {
        cout << "CPig()" << endl;
    }
    
    CPig(int weight) : CAnimal(3), mWeight(weight)
    {
        cout << "CPig(" << weight << ")" << endl;
    }
    
    CPig(const CPig &other) : CAnimal(other), mWeight(other.mWeight)
    {
        cout << "CPig(const CPig &other)" << endl;
    }
    
private:
    int mWeight;
};

class CDonkey : public CAnimal
{
public:
    CDonkey() : mStrength(40)
    {
        cout << "CDonkey()" << endl;
    }
    
    CDonkey(int strength) : CAnimal(4), mStrength(strength)
    {
        cout << "CDonkey(" << strength << ")" << endl;
    }
    
    CDonkey(const CDonkey &other) : CAnimal(other), mStrength(other.mStrength)
    {
        cout << "CDonkey(const CDonkey &other)" << endl;
    }
    
private:
    int mStrength;
};

class CHorse : public CAnimal
{
public:
    CHorse() : mSpeed(50)
    {
        cout << "CHorse()" << endl;
    }
    
    CHorse(int speed) : CAnimal(5), mSpeed(speed)
    {
        cout << "CHorse(" << speed << ")" << endl;
    }
    
    CHorse(const CHorse &other) : CAnimal(other), mSpeed(other.mSpeed)
    {
        cout << "CHorse(const CHorse &other)" << endl;
    }
    
private:
    int mSpeed;
};

class CFarmLand
{
public:
    CFarmLand() : mArea(5000)
    {
        cout << "CFarmLand()" << endl;
    }
    
    CFarmLand(int area) : mArea(area)
    {
        cout << "CFarmLand(" << area << ")" << endl;
    }
    
    CFarmLand(const CFarmLand &other) : mArea(other.mArea)
    {
        cout << "CFarmLand(const CFarmLand &other)" << endl;
    }
    
private:
    int mArea;
};

class CFarm : public CFarmLand
{
public:
    CFarm() : mCapacity(1000)
    {
        cout << "CFarm()" << endl;
    }
    
    CFarm(int capacity) : mCapacity(capacity), mDog(20), mCat(30), mPig(40), CFarmLand(8000)
    {
        cout << "CFarm(" << capacity << ")" << endl;
    }
    
    CFarm(const CFarm &other) : mCapacity(other.mCapacity), mDog(other.mDog), mCat(other.mCat), mPig(other.mPig), CFarmLand(other)
    {
        cout << "CFarm(const CFarm &other)" << endl;
    }
    
private:
    int mCapacity;
    
private:
    CPig mPig;
    CDog mDog;
    CCat mCat;
};

初始化顺序

void construct()
{
    cout << "-----1-start-----" << endl;
    CFarm farm1;
    cout << "-----1-end-----" << endl;
    
    cout << "-----2-start-----" << endl;
    CFarm farm2(2000);
    cout << "-----2-end-----" << endl;
    
    cout << "-----3-start-----" << endl;
    CFarm farm3 = farm2;
    cout << "-----3-end-----" << endl;
}
output:
-----1-start-----
CFarmLand()
CAnimal()
CPig()
CAnimal()
CDog()
CAnimal()
CCat()
CFarm()
-----1-end-----
-----2-start-----
CFarmLand(8000)
CAnimal(3)
CPig(40)
CAnimal(1)
CDog(20)
CAnimal(2)
CCat(30)
CFarm(2000)
-----2-end-----
-----3-start-----
CFarmLand(const CFarmLand &other)
CAnimal(const CAnimal &other)
CPig(const CPig &other)
CAnimal(const CAnimal &other)
CDog(const CDog &other)
CAnimal(const CAnimal &other)
CCat(const CCat &other)
CFarm(const CFarm &other)
-----3-end-----
结论:
  • 数据成员类型分两类:非类类型和类类型
  • 初始化列表可显式初始化父类和数据成员,也可隐式初始化父类和数据成员
  • 显式初始化:父类显式调用合适构造函数,类类型成员显式调用合适构造函数,非类类型成员显式初始化
  • 隐式初始化:父类隐式调用默认构造函数,类类型成员隐式调用默认构造函数,非类类型成员隐式初始化
  • 非类类型成员隐式初始化是什么也不做的初始化,因此隐式初始化的非类类型成员无值,在性能和安全之间c++选择性能
  • 数据成员初始化顺序与数据成员在类中定义顺序一致,与初始化列表中初始化式顺序无关
  • 初始化列表确保对象的每个部分(父类,数据成员)都得到合适初始化,因此初始化列表中父类和类类型成员必须调用合适构造函数,如果调用默认构造函数,可显式调用,也可隐式调用,对于非类类型成员,可显式初始化,也可隐式初始化,尽管非类类型成员隐式初始化什么也不做,但c++认为也完成了初始化,尽管无值不安全
  • 初始化只与初始化列表有关,与函数体无关,进入函数体前,对象的每个部分(父类,数据成员)都必须得到合适初始化,c++认为访问未完全初始化对象是不安全的
  • 子类初始化列表和构造函数函数体可引用父类数据成员(只要访问权限允许),但不可在子类初始化列表中再次初始化父类数据成员,否则父类数据成员多次初始化
  • 类继承体系中构造函数顺序:父类构造函数(初始化列表->函数体)->子类构造函数(初始化列表->函数体)

默认构造函数

  • 误解——默认构造函数是无参构造函数
  • 正解——默认构造函数是无需传递参数就可调用的构造函数,包括无参构造函数和有参但所有参数含默认实参值的构造函数

合成默认构造函数

如果没有显式定义构造函数,编译器会合成默认构造函数,一旦显式定义了构造函数(即使没有实现),编译器不再合成默认构造函数,编译器认为开发者知道怎么构造对象,不再需要编译器的帮助,编译器合成默认构造函数目的是为了使类类型对象支持默认初始化
合成默认构造函数初始化列表中父类调用默认构造函数,类类型成员调用默认构造函数,非类类型成员隐式初始化,确保对象的每个部分都得到合适初始化,合成默认构造函数函数体为空
class CAdvanceFarm : public CFarm
{
private:
    CHorse mHorse;
    CDonkey mDonkey;
};
CAdvanceFarm没有显式定义构造函数,编译器会合成默认构造函数,合成默认构造函数为:
CAdvanceFarm() : CFarm(), mHorse(), mDonkey() {}
void construct()
{
    CAdvanceFarm farm;
}
output:
CFarmLand()
CAnimal()
CPig()
CAnimal()
CDog()
CAnimal()
CCat()
CFarm()
CAnimal()
CHorse()
CAnimal()
CDonkey()
注:对于合成默认构造函数,必须确保父类和类类型成员能调用默认构造函数,否则编译错误,因为不符合“c++的构造函数(初始化列表)确保对象的每个部分(父类,数据成员)都得到合适的初始化”原则

复制构造函数

复制构造函数是构造函数的一个特殊版本,形参列表为[const] classname &,当实例对象复制初始化时调用,复制构造函数与普通构造函数无本质区别,只是其形参特定而已

合成复制构造函数

如果没有显式定义复制构造函数,编译器会合成复制构造函数,一旦显式定义了复制构造函数(即使没有实现),编译器不再合成复制构造函数,编译器认为开发者知道怎么复制对象,不再需要编译器的帮助,编译器合成复制构造函数目的是为了使类类型对象支持复制初始化
合成复制构造函数形参列表为const classname &,初始化列表中父类调用复制构造函数,类类型成员调用复制构造函数,非类类型成员复制初始化,确保对象的每个部分都得到合适初始化,合成复制构造函数函数体为空
class CAdvanceFarm : public CFarm
{
private:
    CHorse mHorse;
    CDonkey mDonkey;
};
CAdvanceFarm没有显式定义复制构造函数,编译器会合成复制构造函数,合成复制构造函数为:
CAdvanceFarm(const CAdvanceFarm &other) : CFarm(other), mHorse(other.mHorse), mDonkey(other.mDonkey) {}
void copyConstruct()
{
    cout << "-----construct-----" << endl;
    CAdvanceFarm farm;
    cout << "-----copy construct-----" << endl;
    CAdvanceFarm copyFarm = farm;
}
output:
-----construct-----
CFarmLand()
CAnimal()
CPig()
CAnimal()
CDog()
CAnimal()
CCat()
CFarm()
CAnimal()
CHorse()
CAnimal()
CDonkey()
-----copy construct-----
CFarmLand(const CFarmLand &other)
CAnimal(const CAnimal &other)
CPig(const CPig &other)
CAnimal(const CAnimal &other)
CDog(const CDog &other)
CAnimal(const CAnimal &other)
CCat(const CCat &other)
CFarm(const CFarm &other)
CAnimal(const CAnimal &other)
CHorse(const CHorse &other)
CAnimal(const CAnimal &other)
CDonkey(const CDonkey &other)
注:对于合成复制构造函数,必须确保父类和类类型成员能调用复制构造函数,否则编译错误,因为不符合“c++的构造函数(初始化列表)确保对象的每个部分(父类,数据成员)都得到合适的初始化”原则

复制构造函数形参的const修饰

class CAnimal
{
public:
    CAnimal() : mGroup(0)
    {
        cout << "CAnimal()" << endl;
    }
    
    CAnimal(int group) : mGroup(group)
    {
        cout << "CAnimal(" << group << ")" << endl;
    }
    
    CAnimal(CAnimal &other) : mGroup(other.mGroup)
    {
        cout << "CAnimal(const CAnimal &other)" << endl;
    }
    
private:
    int mGroup;
};
void copyConstruct()
{
    cout << "-----construct-----" << endl;
    const CAnimal animal(1);
    cout << "-----copy construct-----" << endl;
    //CAnimal copyAnimal = animal;
}
自定义复制构造函数的形参不带const修饰时,编译器不再合成const版本的复制构造函数,编译器认为开发者知道怎么复制对象,不再需要编译器的帮助
复制构造函数总结:
  • 复制构造函数与普通构造函数无本质区别,只是其形参列表为[const] classname &而已,当实例对象复制初始化时调用
  • 合成复制构造函数的形参列表为const classname &,初始化列表中父类调用复制构造函数,类类型成员调用复制构造函数,非类类型成员复制初始化
  • 显式复制构造函数如果形参列表声明为classname &,编译器不再合成复制构造函数,编译器认为开发者知道怎么复制对象,不再需要编译器的帮助

你可能感兴趣的:(cpp)