前一种是使用初始化列表,后一种是在构造函数中进行赋值。
- 先看简单类成员的初始化:
class Animal
{
public:
Animal(int weight,int height): //A初始化列表
m_weight (weight),
m_height (height)
{
}
Animal(int weight,int height) //B函数体内初始化
{
m_weight = weight;
m_height = height;
}
private:
int m_weight ;
int m_height ;
};
列表初始化和函数体内进行初始化都很简单,而且效率上也差不多(当然,上面只是为了说明问题而写的代码,上面两种方式是不能共存的)。
- 再看看继承关系中的构造函数:
class Animal
{
public:
Animal(int weight,int height): //没有提供无参的构造函数
m_weight (weight),
m_height (height)
{
}
private:
int m_weight ;
int m_height ;
};
class Dog: public Animal
{
public:
Dog(int weight,int height,int type) //error 构造函数 父类Animal无合适构造函数
{
}
private:
int m_type ;
};
在这里可以看到,下面那种方法是错误的,这是因为在继承的时候,是先调用父类的构造函数,再调用子类的构造函数。但是发现父类没有默认的构造函数,因此会出错。
所以我们正确的做法是:
class Dog: public Animal
{
public:
Dog(int weight,int height,int type):
Animal (weight, height) //必须使用初始化列表增加对父类的初始化
{
}
private:
int m_type ;
};
- const成员必须在初始化列表中初始化
很简单,const成员是不可以修改的,因此只可以在初始化列表中进行初始化。
class Dog: public Animal
{
public:
Dog(int weight,int height,int type):
Animal (weight, height),
LEGS (4) //必须在初始化列表中初始化
{
//LEGS = 4; //error
}
private:
int m_type ;
const int LEGS;
};
- 自定义成员在初始列表中进行初始化时将大大提升效率
class Food
{
public:
Food(int type = 10)
{
m_type = 10 ;
}
Food(Food &other) //拷贝构造函数
{
m_type = other. m_type;
}
Food & operator =( Food &other ) // 重载赋值=函数
{
m_type = other. m_type;
return * this;
}
private:
int m_type ;
};
class Dog: public Animal
{
public:
Dog(Food &food)
{
m_food = food; //初始化 成员对象
}
private:
Food m_food;
};
如果采用上面的方式,那么实际上会先执行对象类型构造函数 Food(int type = 10),然后执行对象类型构造函数 Food & operator =(Food &other)。
Think about why...
class Dog: public Animal
{
public:
Dog(Food &food)
:m_food (food) //初始化 成员对象
{
//m_food = food;
}
private:
Food m_food;
};
在上面的代码中应该是直接调用拷贝构造函数完成初始化的……