鱼C论坛

 找回密码
 立即注册
查看: 1567|回复: 6

C++构造函数初始化列表

[复制链接]
发表于 2016-4-2 12:36:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
必须对没有默认构造函数的类类型的任何成员使用初始化式      怎么理解啊啊啊 啊啊

我查了,看了点但还是不怎么理解。目前我理解的是 在继承关系中,若父类没有默认构造函数,那么子类的构造函数得使用初始化列表,(我觉得这个只在子类中让他使用父类的有参数的构造函数也能解决吧)  还有引用和const成员数据得用初始化列表

是不是就这些啊。

问一下像这样的
class Base
{
public:
    Base(int b);
    int old
    int date;
};

Base::Base(int b)
{
        old=b;
}

int main(void)
{   
    Base(5);
    return 0;
}

没有默认构造函数,在Base(int b) 里我没有用初始化列表初始化date,只在函数体里对Base初始化,也能通过编译呀。

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-4-2 17:19:07 | 显示全部楼层
本帖最后由 muyu0096 于 2016-4-2 17:20 编辑

他说的是子类需要用初始化列表来为继承自父类的类成员赋值。
子类在创建对象的时候,也就是调用子类构造函数的过程是这样的:
先读取函数头,也就是——先调用父类的构造函数创建继承自父类的对象部分,然后再调用子类增加的部分完成对象的创建——到此为止,读完函数头,(但注意没有进入到函数体),   最后再执行{}--也就是中括号里的函数实现部分的代码。
如果父类有默认构造函数,那么直接调用,因为无需传递参数。
如果父类的默认构造函数被重载,那么子类对象创建的时候,调用重载的构造函数创建父类部分,但问题来了,需要知道传递进去的参数,但这时候,还没有执行到函数体,所以不能在函数体中进行参数传递,所以只能通过参数列表进行参数传递。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-4-2 18:12:22 | 显示全部楼层
muyu0096 发表于 2016-4-2 17:19
他说的是子类需要用初始化列表来为继承自父类的类成员赋值。
子类在创建对象的时候,也就是调用子类构造函 ...

能解释下 读完函数头(但没有进入到函数体)还有 需要知道传递进去的参数,但这时候,还没有执行到函数体,所以不能在函数体中进行参数传递,所以只能通过参数列表进行参数传递 吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-3 14:58:39 | 显示全部楼层
本帖最后由 muyu0096 于 2016-4-3 15:06 编辑
奥古斯丁少爷 发表于 2016-4-2 18:12
能解释下 读完函数头(但没有进入到函数体)还有 需要知道传递进去的参数,但这时候,还没有执行到函数体 ...


以你的代码为例,假设我这么写,
Son:;Son(int b,int s)
{
       Base(b);
      m_son=s;
}
在创建子类对象的时候会调用该构造函数,具体的过程是当编译器读完函数头部分--即中括号前面的部分的时候,就应该完成了对象的建立(申请内存空间,明确变量类型等),然后才执行函数体部分。
如果像上面我写的那样,因为Base(b)在函数体内,所以编译器此时不知道如何创建基类部分。
同样的,非静态const成员变量,即使不是继承来的,同样要用初始化列表来赋值,因为const变量必须创建时就有初值,如果不用列表赋值,那么创建对象的时候,只会给该const变量分配一块内存,其值可能是任何值(看那块地址上原来是啥了...),然后才能在函数体中为这个变量赋值。这违背了const变量必须在创建时就有初值的设定,因此。。。
结合这个,可能好理解些。
关键就在于这个顺序
不太准确的说,函数头赋值创建对象,并分配地址,函数体里完成赋值,如果需要在创建的时候就完成赋值,那么只能通过初始化列表来完成。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-4-3 16:22:17 | 显示全部楼层
muyu0096 发表于 2016-4-3 14:58
以你的代码为例,假设我这么写,
Son:;Son(int b,int s)
{

我在网上找到一种方法
当父类有多个构造函数时,子类在默认情况下会使用父类的默认构造函数,但我们有时需要选择调用哪一个构造函数,
用   子类构造函数应当这样声明  子类名::子类名(参数):父类名(参数);

所以我才觉得父类没有默认构造函数也可以不用初始化列表
下面是我试过的:
#include<iostream>
class Animal
{
public:
    Animal(int a,int b);
    int head;
    int foot;
};

class Bird:public Animal
{
public:
    Bird();
};
Animal::Animal(int a,int b)
{
    head=a;
    foot=b;
}
Bird::Bird():Animal(1,2)//就是这里
{
    ;
}
int main(void)
{
    Bird bird;
    std::cout<<bird.head<<"\n";
    std::cout<<bird.foot;
    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-4-3 16:25:38 | 显示全部楼层
奥古斯丁少爷 发表于 2016-4-3 16:22
我在网上找到一种方法
当父类有多个构造函数时,子类在默认情况下会使用父类的默认构造函数,但我们有时 ...

并且,在子类的函数体里加上需要的基类的构造函数的话,
Son:;Son(int b,int s)
{
       Base(b);
      m_son=s;
}
这是在有默认构造函数的情况下才行,但是这个并不是调用Base(b)来初始化基类的内容,而是调用基类的默认构造函数后,再用Base(b)进行覆盖,这样不好吧,还是上面的那个方法好。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-3 17:30:45 | 显示全部楼层
奥古斯丁少爷 发表于 2016-4-3 16:25
并且,在子类的函数体里加上需要的基类的构造函数的话,
Son:;Son(int b,int s)
{

不是不好,是不行,我假设的一个错误例子
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-26 22:35

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表