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

解决方案

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

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

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

解决方案二:

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

解决方案三:

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

解决方案四:

第一种是用参数初始化列表进行初始化,第二种是函数体内赋值。针对引用,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类有默认构造函数,有默认拷贝构造函数。

}

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

解决方案五:

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

 class Animal
{
public:
  .
private:
    int m_weight  = 1;
    int m_height  = 2;
};
时间: 2025-01-20 19:25:43

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

windows-有谁知道这两种exe软件启动方式的区别是什么吗?

问题描述 有谁知道这两种exe软件启动方式的区别是什么吗? windows下开机自启动一个软件,一个是放在启动项里启动,一个是写入注册表中启动,这两者原理的区别是什么? 解决方案 这个是历史问题造成的. 在Windows 3.1中 来个图吧.你看到,有一个叫Startup的组,这是Windows 3.1的启动程序的方式.那时候还没有注册表.注册表是Windows 95引入的. 但是出于兼容性的需要,微软以后又不得不保留这个"启动",这就造成了开机启动有多个方式.除了你说的这两种之外,其

c++-跳转表用两种不同的实现方式,为什么效率差别大?

问题描述 跳转表用两种不同的实现方式,为什么效率差别大? 题目更新得更详细了,请留意: 在书上看到的跳转表,实现的方式是每层都用一个特殊的List,它的节点连接上下左右: template <typename T> struct QuadlistNode { T data; QuadlistNode<T>* pred; QuadlistNode<T>* succ; //前驱.后继 QuadlistNode<T>* above; QuadlistNode<

数据-毕设,设计一个可视化的管理系统,要求有单机版、网络版两种,请问用什么开发比较合适?急求回答,谢谢~

问题描述 毕设,设计一个可视化的管理系统,要求有单机版.网络版两种,请问用什么开发比较合适?急求回答,谢谢~ 毕业设计,设计一个管理系统,要求有单机版.网络版两种. 单机版可以直接进行数据输入.数据导出 网络版可以数据同步.数据查询 现在比较没有思路,单机版和网络版要用什么来开发? 打算单机的数据库使用SQLITE 网络版的用MYSQL 可视界面用什么开发?VC? 怎样选择开发工具,才能使单机到网络版的可移植性最高啊- - 解决方案 这个很简单,将数据库访问层抽象出来,抽象成一个接口. 业务和界

link以下两种写法结果一样,有什么区别?

问题描述 link以下两种写法结果一样,有什么区别? 写法1: scores.GroupBy(x=>x.StuID).OrderBy(x =>x.Sum()).ThenBy(x => x.Key) 写法2: scores.GroupBy(x=>x.StuID).OrderBy(x =>x.Key).OrderBy(x=>x.Sum()) 解决方案 写法2不推荐,理论上这个结果和写法1一样,但是基于这样一个假设,那就是OrderBy执行的是稳定的排序. 所谓稳定的排序,就

常见的两种软文写作方式

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 笔者近期一直在做软文的写作,经常在A5站长网进行软文投稿,自己也总结了两种常用的软文写作方式.软文可谓是让很多站长非常头疼的一件事情,现在很多资深的站长都经常强调软文的重要性,那么什么是软文?有哪些巧妙的软文写作方式呢?软文相对于硬性广告来讲,软文之所以被称为软文,其特点就在于"软"字,就好比是绵里藏针,藏而不漏,可谓是影

SQL两种简单分页查询方式

                   以前我们或许都用过了linq的skip and take方式进行分页查询,但是很少自己写sql的分页查询,因为大多数时候,我们都是在调用别人的方法.              最近看到一个文档,感觉方法里面实现的分页查询进入数据库调用的时候,实际最底层调用的还是SQL的分页查询,例如,我们用linq写个分页查询,转成sql表达式后发现:                               实际调用的时候,才发现SQL底层是这样进行分页的.      

Environment.Exit()和Process.GetCurrentProcess().Kill()这两种退出进程的方式,有细节上的区别吗?

问题描述 比如,释放资源的区别?在AppDomain里面如果启动了多个exe的assembly的时候,这两种调用有什么区别? 解决方案 解决方案二:求解释!......

asp Driver和Provider两种连接字符串连接Access时的区别_数据库相关

一个网站程序,在添加新闻时出现错误 以下是错误提示: Microsoft OLE DB Provider for ODBC Drivers 错误 '80040e21' 多步 OLE DB 操作产生错误.如果可能,请检查每个 OLE DB 状态值.没有工作被完成. 出现这种错误的原因是因为我把access连接字符串修改为"Driver={Micorsoft Access Driver ()};dbq=" & Server.Mappath(DbPath),而原来的连接字符串为&qu

asp Driver和Provider两种连接字符串连接Access时的区别

一个网站程序,在添加新闻时出现错误 以下是错误提示: Microsoft OLE DB Provider for ODBC Drivers 错误 '80040e21' 多步 OLE DB 操作产生错误.如果可能,请检查每个 OLE DB 状态值.没有工作被完成. 出现这种错误的原因是因为我把access连接字符串修改为"Driver={Micorsoft Access Driver ()};dbq=" & Server.Mappath(DbPath),而原来的连接字符串为&qu