我有以下代码:
class A {
private:
int i;
};
class B : public A {
private:
int j;
};
当我检查sizeof(B)
时,它似乎是sizeof(base) + sizeof(derived)
。但是,我对继承的理解是基类的private
成员不会被继承。为什么它们会包含在sizeof(B)
的结果中?
答案 0 :(得分:8)
所有成员变量都是继承的。 private protected public
修饰符只会改变访问到那些变量的人
答案 1 :(得分:5)
你误解了private
的作用。在您的代码段中,它只会阻止A
的非成员和非朋友访问i
。它只是一个访问控制修饰符。 B
的实例将包含A
的数据成员,即使B
不会(直接)访问它。
这个比喻表明这确实有意义:
class Human
{
protected:
void UseCognitivePowers() { brain.Process(); }
private:
Brain brain;
// ...
};
class StackOverflowUserInSilico : public Human
{
private:
void AnswerStackOverflowQuestion(int questionId)
{
// ...
// magic occurs here
// ...
UseCognitivePowers();
}
};
即使brain
上的Human
是私有的,StackOverflowUserInSilico
也会Brain
,因为StackOverflowUserInSilico
来自Human
。这是必需的,否则UseCognitivePowers()
函数将无效,即使StackOverflowUserInSilico
从Human
继承了该方法。
当然Human
的子类是否会实际利用UseCognitivePowers()
类提供给它们的Human
方法是完全不同的事情。
答案 2 :(得分:4)
您要么误解sizeof
,要么误解C ++对象的布局(在内存中)。
出于性能原因(为了避免间接成本),编译器通常会使用Composition实现Derivation:
// A
+---+
| i |
+---+
// B
+---+---+
| A | j |
+---+---+
请注意,如果private
,B
无法查看A
,即使它包含它。
sizeof
运算符将返回B
的大小,包括必要的填充(用于校正校正),如果有的话。
如果您想了解更多信息,我衷心建议 Stanley A. Lippman Inside the C++ Object Model。虽然编译器依赖,但许多编译器确实使用相同的基本原理。
答案 3 :(得分:3)
它是继承的 - 派生类对象将包含它,但派生类的成员函数无法访问它。
答案 4 :(得分:2)
在其他一些答案中已经回答了这个问题:访问说明符限制访问,但该类的成员属性仍然是继承的。
我只想提供一个理由,因为当我看到原因时,我通常会学得更好。基本上,当您从类型继承时,派生类型包含基类型的子对象,与基类可能一样小或大。 需要所有成员变量的原因是派生对象是基础对象,并且可以在其上调用基本级别成员函数。即使派生类型无法访问私有成员属性,可以在该对象上调用的基本方法仍然需要访问它,因此成员必须在那里:
class base {
int x;
public:
base() : x(0) {}
// ...
void printout() {
std::cout << x << std::endl;
}
};
class derived : public base {
// ... assume that derived does not hide `printout`
};
int main() {
derived d;
d.printout(); // this requires access to d.base::x
}
这只是一个简单的例子,你可以在这里说几件事来争辩说在某些情况下x
可以不需要(我们正在覆盖/隐藏{派生对象中的{1}} ...但该语言仍然允许您通过限定访问隐藏/重写的成员方法,因此printout
仍然可以在基础级别访问d.base::printout()
,并且轮流需要printout
。
答案 5 :(得分:0)
访问说明符(public / private / protected)不会影响继承的“对象大小”。
答案 6 :(得分:0)
我不知道这是什么语言,但是当你继承原始对象时仍然存在。这就是为什么你仍然可以调用base.method()