关于C++初始化列表的一种特殊用法

受助于许许多多的博客文章,第一次回馈!写得不好,请多见谅。

关于C++初始化列表的一种特殊用法

万恶之源

Canvas::Canvas(Gwen::Skin::Base* pSkin) : BaseClass(NULL), m_bAnyDelete(false), m_fScale(-1)
{
	SetBounds(0, 0, 10000, 10000);
	SetSkin(pSkin);
	SetScale(1.0f);
	SetBackgroundColor(Color(255, 255, 255, 255));
	SetDrawBackground(false);
}

这是今天在看bullet3源码时,发现的一点不解之处。
BaseClass(NULL)
正常来说,在初始化列表这个位置,像m_bAnyDelete(false), m_fScale(-1)
都是初始化一个变量的作用。
但是,这里的BaseClass却是一个类。
不解。

为了方便,我复现了代码:

#include <iostream>

class A
{
public:
    A(int* n)
    {
        printf("调用 A 的构造函数\n");
    }
};

class B : public A
{
    int k;
public:
    B() : A(NULL), k(1)
    {
        printf("调用 B 的构造函数\n");
    }
};

int main()
{
    B b;

    return 0;
}

在与舍友的讨论之下,他的一句话启发了我:“你的A是基类 不是成员。。”
我恍然大悟:
基类!
在类的构造函数被调用的时候,首先是跳到基类的构造函数上去的。
那么,在构造函数这里的初始化列表,出现了基类,是否意味着什么呢?
噎死!(yes)

首先我删除了A(NULL)这部分,然后编译失败:不存在默认构造函数。
!!!
那就是说,如果加了A(NULL)这部分,那么在类调用构造函数时候,它调用的基类的构造函数,将不是默认构造函数,而且有参数版本!!!
因为一般来说,都是不加A(NULL)的,自然调用的基类的构造函数,是默认版本。
!!!!!!!!!!!
那么A(NULL)这个部分的作用,就不是“初始化”了,而且“指定基类的构造函数”了。

21:44:27
那么,原本没写A(NULL),是调用 A() 这个构造函数的,
如果写了 A(NULL),那么就调用 A(int* n) 这个构造函数。
21:44:48
区别就是:调用不同的 基类的 构造函数。

来执行:不同的 对基类成员的 初始化操作。
比如默认构造函数是 a=1
换成另一个构造函数,就是 a=2

就是这个区别。

在补了默认构造函数之后,不加A(NULL)也不报错了。
加了如下代码:
after added
则结果显示上图的printf语句。(红框里的“—”只是为了方便区分)



加了A(NULL)之后,则调用的是基类的A(int* n)这个版本的构造函数。




21:50:39
“执行基类的非默认构造函数”
这只有初始化列表,才能这样子做。
没有其他办法。

21:55:04
如果以后公司让你面试新人,可以出这个题了 哈哈哈哈哈哈哈哈哈哈
问他们:在构造函数的初始化列表中,“对类型进行初始化”是毛意思。
答:这不是对类型初始化,而且对基类调用非默认构造函数,因为如果不写,那就调用默认构造函数。

. 21:57:09
其实没啥特别的,你这里的 B的构造函数 就是调用基类的构造函数了而已,参数为NULL

. 21:57:18
B的初始化列表 必须要初始化A

. 21:57:27
除非你的A里面有 不带参数 的构造函数

. 21:57:40
就是 说 无论如何 你也要初始化A才能完事

21:58:03
特别就在这里:“执行基类的非默认构造函数”
“非默认构造函数”

21:58:41
这个写法,很容易让人误以为是赋值操作啊

21:59:07
毕竟位置是“初始化列表”,听名字就是用来初始化的

21:59:29
鬼知道还能“调用基类的构造函数”


后期补充:
C++派生类中调用基类成员函数和构造函数
https://www.jianshu.com/p/6bc25c22a1df
假设这样一个情况,我们在派生类的构造函数中,希望调用基类的构造函数,但基类没有和派生类构造函数参数相匹配的构造函数。例如下面:

class Base {
public:
    Base(int i) { // 基类没有默认构造函数,当前构造函数仅接受一个参数
        cout << "调用基类构造函数" << endl;
    };
};

class Derived : public Base {
public:
    Derived(int i, int j) { // 派生类构造函数接受两个参数,语法错误,no default constructor exists for class Base
        cout << "调用派生类构造函数" << endl;
    };
};

默认情况下,派生类会调用基类相同参数的构造函数,但这里没有相同参数的构造函数,便会有语法错误,即时我们在派生类的构造函数里调用Base::Base()也不行。解决方法是,在派生类构造函数的初始化列表里调用基类的构造函数,如下:

class Base {
public:
    Base(int i) { // 基类没有默认构造函数,当前构造函数仅接受一个参数
        cout << "调用基类构造函数" << endl;
    };
};

class Derived : public Base {
public:
    Derived(int i, int j): Base(i) { // 派生类构造函数接受两个参数,语法错误,no default constructor exists for class Base
        cout << "调用派生类构造函数" << endl;
    };
};

int main()
{
    Derived d(1, 2);
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值