派生类初始化列表无法初始化基类变量

stackoverlow 2011-11-02 05:27:03

class A
{
protected:
int a;
};
class B:public A
{
public:
B():a(5) { }
};
int main()
{
B q;
return 0;
}

今天突然发现的,不知道怎么回事。按道理保护成员继承后就相当于派生类的私有成员了吧。那为什么不能在初始化列表里初始化基类的成员?把初始化放到函数体里就行,放到初始化列表就报错。。
error C2614: 'B' : illegal member initialization: 'a' is not a base or member
求解这是为什么啊?
...全文
665 24 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
vichal 2011-12-08
  • 打赏
  • 举报
回复
构造函数的顺序是先调用基类的构造函数,然后调用子类的构造函数,所以在子类的构造函数调用之前,父类的成员都已经构造完毕并初始化完毕。再进行初始化没有意义,所以只能进行赋值。
pathuang68 2011-11-03
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 xuqiqw 的回复:]

引用 6 楼 pathuang68 的回复:
如果要初始化A中的那个a,那么就需要用到A的构造函数,可以这么写:

C/C++ code


#include <iostream>
using namespace std;
class A
{
protected:
int a;
public:
A(int a)
{
this->a = a;
}
};

cl……
[/Quote]

"我很疑惑a既然对B可见,为什么不能用初始化列表来初始化它而必须要放在函数体内用?我一直是以如果是保护成员的话继承过来就相当于派生类的私有成员来理解的。。结果这里不解了"

红色字体的认识是错误的。基类的protected成员如果是用public方式继承的话,那么在派生类中它依然是protected的,形如:
class Derived : public Base
如果用private继承的话,在派生类中它就是private的,形如:
class Derived : private Base

"我很疑惑a既然对B可见",通过上面的分析,不管a在派生类B中是protected还是private的,在B类中都是可见的,楼主何言其不可见。

protected成员变量在类定义的外部是不可见的,比如:
A objA;
objA.a = 10; // 此时a是不可见的

建议楼主找本C++的书,看看继承这方面的内容。

zhanglingkangk 2011-11-03
  • 打赏
  • 举报
回复
在派生类中,从基类继承来的成员的初始化必须有基类的构造函数完成
include <iostream>
using namespace std;
class A
{
protected:
int a;
};

class B:public A
{
public:
B()
{
a = 5 ;//这个叫赋值。不叫初始化,所以可以。

}

void printinfo()
{
cout << a << endl;
}
};

int main()
{
B q;
q.printinfo();
return 0;
}

shao_929 2011-11-03
  • 打赏
  • 举报
回复
保持原有属性,我在说a的时候跟上面的继承没关系~~~理解,
因为举的例子a刚好是保护的,所以就说a是类A的保护成员~~
这样理解了吗??
qunqun2012 2011-11-03
  • 打赏
  • 举报
回复
你得逻辑就是 public成员 就可以初始化??

[Quote=引用 20 楼 shao_929 的回复:]
我晕,这问题会这么多奇异,看来LZ该好好查看下继承哪里的知识。。
如果是公有继承,则继承下来的成员变量保持原有属性;
私有继承则会把继承下来的成员变量在子类中转化为私有;
当然保护转保护~~~
而a是类A的保护成员,这么能在B里面来初始化呢,搞笑了。。
要不就调用A的初始化来初始化。。。。
[/Quote]
shao_929 2011-11-03
  • 打赏
  • 举报
回复
我晕,这问题会这么多奇异,看来LZ该好好查看下继承哪里的知识。。
如果是公有继承,则继承下来的成员变量保持原有属性;
私有继承则会把继承下来的成员变量在子类中转化为私有;
当然保护转保护~~~
而a是类A的保护成员,这么能在B里面来初始化呢,搞笑了。。
要不就调用A的初始化来初始化。。。。
caddor2011 2011-11-03
  • 打赏
  • 举报
回复

原来如此,, 初始化 赋值 概念 在派生类的构造函数中体现到了

以前没有意识到。。。。。

好帖子

哈哈

赚到了




[Quote=引用 18 楼 chenpping 的回复:]
引用 16 楼 caddor2011 的回复:
不解

我说说自己的愚见,不对清指教

总结一下: trivial这个单词,差了一下,是琐碎, 微不足道的意思。。。

primer中说过,

举个例子说吧

class A
{
int a;

A(){}

};

A a;
对于全局对象而言,a会被初始化为0的

对于非全局,则是 随即的。。。。

……
[/Quote]
chenpping 2011-11-03
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 caddor2011 的回复:]
不解

我说说自己的愚见,不对清指教

总结一下: trivial这个单词,差了一下,是琐碎, 微不足道的意思。。。

primer中说过,

举个例子说吧

class A
{
int a;

A(){}

};

A a;
对于全局对象而言,a会被初始化为0的

对于非全局,则是 随即的。。。。

所以,你说它是trivial,如果是非全局对象,我……
[/Quote]成员初始化列表代表初始化,你对一个已经初始化的a再初始化,你认为会出错吗?所以说派生类不允许对基类的private成员初始化。只能
1:初始化自己的成员
2:调用基类的构造函数初始化基类部分
否则,编译器会报错。
caddor2011 2011-11-03
  • 打赏
  • 举报
回复
没说到正题上


[Quote=引用 14 楼 kingstar158 的回复:]
派生类在构造函数是,首先会调用基类的构造函数
而基类的构造函数执行时,其数据成员都会初始化,而你在派生类的构造函数体进行所谓的初始化,只是赋值而已!
[/Quote]
caddor2011 2011-11-03
  • 打赏
  • 举报
回复
不解

我说说自己的愚见,不对清指教

总结一下: trivial这个单词,差了一下,是琐碎, 微不足道的意思。。。

primer中说过,

举个例子说吧

class A
{
int a;

A(){}

};

A a;
对于全局对象而言,a会被初始化为0的

对于非全局,则是 随即的。。。。

所以,你说它是trivial,如果是非全局对象,我赞同。。。。

2. 请问 你提到的 那个 插入的顺序,


这个B类是楼主住帖子的 B类
B():a(5){}

基类构造函数这里没有显示调用,,而是由编译器来调用。。

楼主主帖之所以错,,,,我猜测是:基类没有构造出来,,所以没有a, 所以导致错误。。。。。。

但是 很矛盾, 基类构造函数已经编译器插入了啊。。。。。对吧???

插入被调用了。。。。会什么 a又不存在呢???

反过来推断我的猜测是错误的,,,, 基类已经构造了。。。

可是构造了,为什么 楼主的代码错了呢?





[Quote=引用 15 楼 chenpping 的回复:]
这个问题是这样的:
问题1,在构造派生类的时候,c++编译器会做什么?
问题2,member initialization list是什么
问题1,当你编写一个派生类的构造函数时,如果你没有(调用基类的默认构造函数)初始化基类部分,而且基类存在默认构造函数的话,编译器会在你的构造函数之前安插基类默认构造函数的代码
问题2,成员初始化列表是什么,成员初始化列表也是类的构造函数的一部分,它是真……
[/Quote]
chenpping 2011-11-03
  • 打赏
  • 举报
回复
这个问题是这样的:
问题1,在构造派生类的时候,c++编译器会做什么?
问题2,member initialization list是什么
问题1,当你编写一个派生类的构造函数时,如果你没有(调用基类的默认构造函数)初始化基类部分,而且基类存在默认构造函数的话,编译器会在你的构造函数之前安插基类默认构造函数的代码
问题2,成员初始化列表是什么,成员初始化列表也是类的构造函数的一部分,它是真正的初始化,编译器会把它安插在你的函数体中。
ok,现在来看下你的代码做了什么,由于你的B的默认构造函数的成员初始化列表中没有调用A的默认构造函数,所以B的构造函数首先调用A的默认构造函数(在本例中A的默认构造函数是一个trivial的)把a初始化为一个随机值,然后调用成员初始化列表啊a(5),好吧,这是非法的。
另外,要记住,在构造函数的函数体内编写的代码是赋值!!!!!!不是初始化,初始化的工作被编译器安插的代码完成了。
追求执着 2011-11-03
  • 打赏
  • 举报
回复
派生类在构造函数是,首先会调用基类的构造函数
而基类的构造函数执行时,其数据成员都会初始化,而你在派生类的构造函数体进行所谓的初始化,只是赋值而已!
stackoverlow 2011-11-03
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 pathuang68 的回复:]
引用 8 楼 xuqiqw 的回复:

引用 6 楼 pathuang68 的回复:
如果要初始化A中的那个a,那么就需要用到A的构造函数,可以这么写:

C/C++ code


#include <iostream>
using namespace std;
class A
{
protected:
int a;
public:
A(int a)
{
this……
[/Quote]
可能我表述不好。。这些我知道我只是自己以这种方式方便理解
不解的地方就像12楼说的

为什么不能在派生类的构造函数参数列表初始化 a啊???
B::B():a(5) {}这样不行

但是却可以
B::B()
{
a=5;
}

chouxiaoya1112 2011-11-03
  • 打赏
  • 举报
回复
为什么不能再派生类的构造函数参数列表初始化 a啊???


你可能说,不可见!!因为它是A的

但是却可以
B::B()
{
a=5;
}



[Quote=引用 1 楼 ouyh12345 的回复:]
调用基类的构造函数
[/Quote]
caddor2011 2011-11-03
  • 打赏
  • 举报
回复
玄机居士

你能回复一下7楼的疑问嘛,

我不是楼主,但是楼主的这个问题,困扰我一天了


肯定是我对继承还没吃透

劳烦你了




[Quote=引用 10 楼 pathuang68 的回复:]
引用 8 楼 xuqiqw 的回复:

引用 6 楼 pathuang68 的回复:
如果要初始化A中的那个a,那么就需要用到A的构造函数,可以这么写:

C/C++ code


#include <iostream>
using namespace std;
class A
{
protected:
int a;
public:
A(int a)
{
this……
[/Quote]
caddor2011 2011-11-02
  • 打赏
  • 举报
回复
同问 ,大神们帮忙解答一下,谢谢了啊

stackoverlow 2011-11-02
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 pathuang68 的回复:]
如果要初始化A中的那个a,那么就需要用到A的构造函数,可以这么写:

C/C++ code


#include <iostream>
using namespace std;
class A
{
protected:
int a;
public:
A(int a)
{
this->a = a;
}
};

cla……
[/Quote]
我很疑惑a既然对B可见,为什么不能用初始化列表来初始化它而必须要放在函数体内用?我一直是以如果是保护成员的话继承过来就相当于派生类的私有成员来理解的。。结果这里不解了
我本来是用一个类继承自一个抽象类,这个数据是抽象类的所以我不想给抽象类提供构造函数想直接在初始化列表初始化它,如果放在函数体内的话等于还是调用了次默认构造函数额
caddor2011 2011-11-02
  • 打赏
  • 举报
回复
本菜鸟记得 primer说过构造函数

class Sample
{
private:
int val;

publci:
Sample(int i)
{
val=i;

}
}

这样 ,不用列表初始化效率低

缘由: 编译器会去 先

Sample(int i):val(0)
{
val=i;
}

这样处理。。。。。

多干了一次。。。。所以效率低。。。。

我说这个事情的 是有用意:

4楼也是被初始化过过

你的代码:
B()
{
a = 5;
}

B 的构造被调用的时候, 会去调用A的构造,,,, A的构造是默认构造。。。
然后给a=0;

再进入函数体内

a=5;




[Quote=引用 6 楼 pathuang68 的回复:]
如果要初始化A中的那个a,那么就需要用到A的构造函数,可以这么写:

C/C++ code

#include <iostream>
using namespace std;
class A
{
protected:
int a;
public:
A(int a)
{
this->a = a;
}
};

class……
[/Quote]
pathuang68 2011-11-02
  • 打赏
  • 举报
回复
如果要初始化A中的那个a,那么就需要用到A的构造函数,可以这么写:

#include <iostream>
using namespace std;
class A
{
protected:
int a;
public:
A(int a)
{
this->a = a;
}
};

class B:public A
{
public:
B():A(5)
{
}

void printinfo()
{
cout << a << endl;
}
};

int main()
{
B q;
q.printinfo();
return 0;
}


可以发现4楼和这里的输出都是5,但内部的机制是有所不同的。
4楼的做法,是先将a继承过来,然后再初始化;
这里的做法,是想a初始化,再继承过来。
caddor2011 2011-11-02
  • 打赏
  • 举报
回复
开始乱了

a 对于B来说也是可见的啊

你的那个例子也说明B有a

其他函数中用a没事,在构造函数中用就有事呢???

难道

B():a(5){}

编译器认为 这里的a是基类的,只允许这样用“

A(int val):a(val){}
B():A(5){}



[Quote=引用 4 楼 pathuang68 的回复:]
引用 3 楼 caddor2011 的回复:

威慑呢么会这样??

我举个例子:

class A
{
public:
void f() const
{
std::cout<<"A"<<std::endl;
}
};



class B:public A
{
public:
void f2() const
{
f();
}

};

对于函……
[/Quote]
加载更多回复(4)

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧