在c ++中派生对象和基础对象之间有什么区别?

时间:2009-11-08 16:17:35

标签: c++ compiler-construction

在c ++中,派生对象和基础对象之间有什么区别,

尤其是当班级中有虚拟功能时。

派生对象是否维护其他表来保存指针

到函数?

10 个答案:

答案 0 :(得分:11)

答案 1 :(得分:2)

理论上,如果从另一个派生一个类,则有一个基类和一个派生类。如果创建派生类的对象,则会有派生对象。在C ++中,您可以多次从同一个类继承。考虑:

struct A { };
struct B : A { };
struct C : A { };
struct D : B, C { };

D d;

d对象中,每个A对象中有两个D个对象,称为“基类子对象”。如果您尝试将D转换为A,那么编译器会告诉您转换是不明确的,因为它不知道哪个 A对象你想转换:

A &a = d; // error: A object in B or A object in C?

如果您命名A的非静态成员,也是如此:编译器会告诉您一个模糊性。在这种情况下,您可以先转换为BC

来规避它
A &a = static_cast<B&>(d); // A object in B

对象d被称为“最派生对象”,因为它不是另一个类类型对象的子对象。为避免上述歧义,您可以继承虚拟

struct A { };
struct B : virtual A { };
struct C : virtual A { };
struct D : B, C { };

现在,只有一个<{1>}类型的子对象,即使你有两个子对象,这个对象包含在:subobject A和子对象{ {1}}。将B对象转换为C现在不明确,因为DA路径上的转换将产生相同的B子对象。

以上是一个复杂的问题:从理论上讲,即使不考虑任何实现技术,CA子对象中的任何一个或两个现在都不再是连续的。两者都包含相同的A对象,但两者都不包含彼此。这意味着其中一个或两个必须“拆分”并仅引用另一个的A对象,以便BC对象可以具有不同的地址。在线性存储器中,这可能看起来像(假设所有对象的大小都是1字节)

B

CC: [1 byte [A: refer to 0xABC [B: 1byte [A: one byte at 0xABC]]]] [CCCCCCC[ [BBBBBBBBBBCBCBCBCBCBCBCBCBCBCB]]]] CB子对象所包含的内容。现在,如您所见,C子对象将被拆分,没有办法,因为B中没有C,反之亦然。使用B函数中的代码访问某些成员的编译器不能只使用偏移量,因为C函数中的代码不知道它是否包含在子代码中object,或 - 当它不是抽象时 - 它是否是一个派生最多的对象,因此它旁边有C个对象。

答案 2 :(得分:1)

public冒号。 (我告诉过你C ++很讨厌)

class base { }
class derived : public base { }

答案 3 :(得分:1)

让我们:

class Base {
   virtual void f();
};

class Derived : public Base {
   void f();
}

没有f是虚拟的(在伪“c”中实现):

struct {
   BaseAttributes;
} Base;

struct {
   BaseAttributes;
   DerivedAttributes;
} Derived;

虚拟功能:

struct {
   vfptr = Base_vfptr,
   BaseAttributes;
} Base;

struct {
   vfptr = Derived_vfptr,
   BaseAttributes;
   DerivedAttributes;
} Derived;

struct {
   &Base::f
} Base_vfptr

struct {
   &Derived::f
} Base_vfptr

对于多重继承,事情变得更复杂:o)

答案 4 :(得分:0)

Derived是Base,但Base不是Derived

答案 5 :(得分:0)

base-是您派生的对象。 derived - 是继承父亲的公共(和受保护)成员的对象。

派生对象可以覆盖(或在某些情况下必须覆盖)他父亲的一些方法,从而创建不同的行为

答案 6 :(得分:0)

基础对象是派生其他人的基础对象。通常它会有一些虚拟方法(甚至是纯虚拟方法),子类可以覆盖它们来专门化。

基础对象的子类称为派生对象

答案 7 :(得分:0)

派生对象派生自其基础对象。

答案 8 :(得分:0)

您是否询问相应对象在内存中的表示?

基类和派生类都有一个指向其虚函数的指针表。根据已覆盖的功能,该表中条目的值将发生变化。

如果B添加了更多不在基类中的虚函数,则B的虚方法表将更大(或者可能有一个单独的表,具体取决于编译器实现)。

答案 9 :(得分:0)

  

在c ++中,派生对象和基础对象之间有什么区别,

可以使用派生对象代替基础对象;它拥有基础对象的所有成员,也许还有更多自己的成员。因此,给定一个函数将引用(或指针)带到基类:

void Function(Base &);

您可以将引用传递给派生类的实例:

class Derived : public Base {};
Derived derived;
Function(derived);
  

尤其是当班级中有虚拟功能时。

如果派生类重写了虚函数,那么即使通过对基类的引用,也会始终在该类的对象上调用被覆盖的函数。

class Base
{
public:
    virtual void Virtual() {cout << "Base::Virtual" << endl;}
    void NonVirtual()      {cout << "Base::NonVirtual" << endl;}
};

class Derived : public Base
{
public:
    virtual void Virtual() {cout << "Derived::Virtual" << endl;}
    void NonVirtual()      {cout << "Derived::NonVirtual" << endl;}
};

Derived derived;
Base &base = derived;

base.Virtual();      // prints "Derived::Virtual"
base.NonVirtual();   // prints "Base::NonVirtual"

derived.Virtual();   // prints "Derived::Virtual"
derived.NonVirtual();// prints "Derived::NonVirtual"
  

派生对象是否维护其他表来保存指向函数的指针?

是 - 两个类都将包含一个指向虚函数表的指针(称为“vtable”),以便在运行时找到正确的函数。您不能直接访问它,但它确实会影响内存中数据的大小和布局。