2 tianliangcsdn tianliangcsdn 于 2016.04.12 09:36 提问

c++下面两种构造函数的实现方式有什么区别?为什么?( 请说详细点 谢谢)
c++

c++下面两种构造函数的实现方式有什么区别?为什么?( 请说详细点 谢谢)
一:Savingaccount::Savingaccount(int date,int id,double rate):id(id),balance(0),rate(rate),lastdate(date),accumulation(0)
{ //构造函数的第一种实现方式

cout<<date<<"\t#"<<id<<"is created"<<endl;

}
二:Savingaccount::Savingaccount(int date,int id,double rate)
{ //构造函数的第二种实现方式
id=id;
balance=0;
rate=rate;
lastdate=date;
accumulation=0;
cout<<date<<"\t#"<<id<<"is created"<<endl;
}

5个回答

noahzuo
noahzuo   2016.04.12 09:52

前一种是使用初始化列表,后一种是在构造函数中进行赋值。

  1. 先看简单类成员的初始化:
 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 ;
};

列表初始化和函数体内进行初始化都很简单,而且效率上也差不多(当然,上面只是为了说明问题而写的代码,上面两种方式是不能共存的)。

  1. 再看看继承关系中的构造函数:
 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 ;
};

  1. 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;
};

  1. 自定义成员在初始列表中进行初始化时将大大提升效率
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 ;
};
  • 构造函数赋值方式 初始化成员对象m_food
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;
};

在上面的代码中应该是直接调用拷贝构造函数完成初始化的……

noahzuo
noahzuo 回复tianliangcsdn: 你应该是新手吧,代码里有些地方还需要改进。最大的问题就是类型转换,你在double和int之间进行了太多操作,来来往往的隐式类型转换可能会带来问题。
一年多之前 回复
noahzuo
noahzuo 回复tianliangcsdn: 你应该是新手吧,代码里有些地方还需要改进。最大的问题就是类型转换,你在double和int之间进行了太多操作,来来往往的隐式类型转换可能会带来问题。
一年多之前 回复
tianliangcsdn
tianliangcsdn 完整代码如下,为什么当我用在构造函数中赋值的方式时是不对的呀?
一年多之前 回复
tianliangcsdn
tianliangcsdn   2016.04.12 10:00

class Savingaccount //个人银行账户管理系统
{
private:
int id;
double balance;
double rate;
int lastdate;
double accumulation;
void record(int date,double amount);
double accumulate(int date)const{
return accumulation+balance*(date-lastdate);
}
public:
Savingaccount(int date,int id,double rate);
int getId(){return id;}
double getBalance(){return balance;}
double getRate(){return rate;}
void deposit(int date,double amount);
void withdraw(int date,double amount);
void settle(int date);
void show();
};
Savingaccount::Savingaccount(int date,int id,double rate)//:id(id),balance(0),rate(rate),lastdate(date),accumulation(0)
{ //构造函数的第二种实现方式
id=id;
balance=0;
rate=rate;
lastdate=date;
accumulation=0;
cout< }
void Savingaccount::record(int date,double amount){
accumulation=accumulate(date);
lastdate=date;
amount=floor(amount*100+0.5)/100;//保留小数点后两位数
balance+=amount;
cout }
void Savingaccount::deposit(int date,double amount){
record(date,amount);
}
void Savingaccount::withdraw(int date,double amount){
if(amount>getBalance())
cout<<"eror:not enough money "<<endl;
else
record(date,-amount);
}
void Savingaccount::settle(int date){
double interest=accumulate(date)*rate/365;
if(interest!=0)
record(date,interest);
accumulation=0;
}
void Savingaccount::show(){
cout<<"#"<<id<<"\tbalance:"<<balance;
}
int main(){
Savingaccount sa0(1,21325302,0.015);
Savingaccount sa1(1,58320212,0.015);
sa0.deposit(5,5000);
sa1.deposit(25,10000);
sa0.deposit(45,5500);
sa1.withdraw(60,4000);
sa0.settle(90);
sa1.settle(90);
sa0.show();cout<<endl;
sa1.show();cout<<endl;
system("pause");
return 0;
}

beifengche
beifengche   2016.04.12 10:08

第一种是使用初始化列表,第二种是在构造函数中进行赋值。前者发生的会更早一些,前者效率会高。类似于下面的代码:
假如我要给a一个初值10;
我可以写成
int a = 10;
也可以写成下面的方式。
into a;
a = 10;

qq_31597573
qq_31597573 回复tianliangcsdn: Savingaccount::Savingaccount(int m_date, int m_id, double m_rate),把参数的名字改改,不要和成员变量名一致,就可以了
一年多之前 回复
tianliangcsdn
tianliangcsdn 上面评论里给出的完整代码用第二种方法为什么运行结果不对呀?
一年多之前 回复
qq_31597573
qq_31597573   2016.04.12 10:19

第一种是用参数初始化列表进行初始化,第二种是函数体内赋值。针对引用,const类型的成员变量,以及没有默认构造函数的自定义数据类型必须用参数初始列表进行初始化。
比如:class School
{
public:
School(int number,int area,Student stu,int location):m_number(number),m_area(area),m_stu(stu)
{
m_location=location;
}
private:
const int m_number;
int& m_area;
Student m_stu;//Student类没有默认构造函数,但是有默认拷贝构造函数。
int m_location;
}
针对School类的前三个数据成员,必须用参数初始化列表进行初始化,如果在类里赋值会报错。而针对内置类型如m_location,参数初始化列表和函数体内赋值没有影响。
另外针对有默认构造函数的自定义成员变量。使用参数初始化列表进行初始化可以提高效率。
比如:
比如:class School
{
public:
School(Student stu):m_stu(stu)//只调用拷贝构造函数
{
// m_stu=stu;//调用构造函数+赋值操作
}
private:
Student m_stu;//Student类有默认构造函数,有默认拷贝构造函数。

}

可以看到参数初始化只执行一次操作,而函数体内赋值则需要两次,所以针对自定义数据类型(一般指类),用参数初始化列表更好。谢谢

sunnyloves
sunnyloves   2016.04.12 13:04

c++11的话直接声明之后就可以初始化了

 class Animal
{
public:
  .
private:
    int m_weight  = 1;
    int m_height  = 2;
};
Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!