接受指向基 class 的指针的函数是否也接受从基 class 私下派生的子 class?

Does a function that takes a pointer to base class also accept a child class that derived privately from the base class?

这是在我的 c++ class 中出现的,假设我们有一个带有一些 public 函数的基础 class。

class basevector {
public:
virtual int indexTo(int arg);
virtual int getSize() const;
virtual int push(int);
virtual int pop(int);
}

然后我们有一个 class 私有派生

class myvector : private basevector{
public :  
virtual int push(int);
virtual int pop(int);
virtual int getSize() const;
}

请注意,myvector class 限制对 indexTo 函数的访问并强制用户使用 push 和 pop。

现在如果我有一个函数接受指向 basevector 的指针

void do_something(basevector * arg) {
    for(int i = 0; i < arg->getSize(); i++) {
        int k = arg->indexTo(i);
        do_something_else(k);
    }
}

然后我尝试执行以下操作

basevector * ptr = nullptr;
ptr = new myvector;

do_something(ptr);

会发生什么? myvector 是一个 basevector 但尝试在 basevector 中使用 public indexTo 函数的函数将在 myvector.[=22 上失败=]

欢迎使用虚函数!每当您将 class 中的函数标记为 virtual 时,您就是在告诉编译器 "Hey, I might override this function later. If I do, then make sure to use the new overridden version!"。它与限制对 class 中函数的访问无关。这就是 public 关键字的作用。

在您的具体示例中,您可以从 basevectormyvector 访问所有四个函数。但是,这些函数代表什么取决于您使用的值的类型(而不是指针的类型!)当您创建一个 new myvector 时,您也创建了一个 table指向它应该使用的函数:

push    --> myvector::push
pop     --> myvector::pop
getSize --> myvector::getSize
indexTo --> basevector::indexTo

最后一个自动发生,因为当您声明 myvector 时,您继承自 basevector。不过,在您对 myvector 的定义中,您已经覆盖了其他三个。

好的。那又怎样?

好吧,当您定义一个采用泛型 basevector 的新函数时,例如 do_something,编译器知道 basevector 具有虚函数。每当它调用其中一个函数时,它都必须查看在创建 basevector 时生成的 table。在您的示例中,table 是 myvector 中的 table。因此,无论您是否传入 basevectormyvector.

do_something 都会调用 basevectorindexTo

你实际上可以强制 myvector来实现它自己的版本indexTo:

class basevector {
  public:
    virtual int indexTo(int arg) = 0;
    /* ... */
};

现在,如果您尝试创建一个 new myvector,编译器会抱怨说它无法在它的虚函数 table 中找到指向它的 indexTo 条目的东西(通常称为"V-table")。

但是,当涉及到私有继承时,你应该这样对待:

class A : private B { ... 

这意味着 "Everything that an A has access to in B will be private to people outside of A"。所以稍后,您可以执行以下操作:

myvector *p1 = new myvector;
basevector *p2;
// p2 = p1;    // <-- Compiler will complain here because we don't know that
               // basevector is a base class of myvector!
p2 = reinterpret_cast<basevector *>(p1);
p2->pop();  // Super hacky but identical to calling p1->pop();

但是,如 this question 中所述,使用私有继承隐藏了 basevector 也是 myvector 的基础 class!因为我们知道它是,所以我们可以转换指针 到 basevector 并引发相同的行为,因为我们知道虚函数是如何工作的。

实际上,使用私有继承时您的代码甚至无法编译。因为 basevector 是私有继承的,所以你根本不能将 myvector* 指针赋值给 basevector* 指针,编译器会抱怨:

Cannot convert 'myvector *' to 'basevector *'

一旦将 private 更改为 public 继承,它就可以正常工作。

但是,假设您可以myvector* 分配给 basevector*indexAt()basevector中声明为public,而do_something()是直接访问basevector,所以可以访问indexAt().

理论上,一个函数不应该关心子 class 或它如何从基类继承,所以假设你有这样一个指针,是的,函数会正常地对其进行操作。然而在实践中,答案是否定的,因为基 class 指针指向子 class 的实例,该实例继承了私有 can't exist.

本质上,私有继承就像秘密继承——子 class 从基础 class 继承的事实是外部不可见的。所以,编译器甚至不会让你做你写的:

basevector * ptr = nullptr;
ptr = new myvector;

因为私有继承规则。