【问题标题】:Does a function that takes a pointer to base class also accept a child class that derived privately from the base class?带有指向基类的指针的函数是否也接受从基类私有派生的子类?
【发布时间】:2015-06-11 11:25:45
【问题描述】:

这出现在我的 c++ 类中,假设我们有一个带有一些公共函数的基类。

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

那么我们有一个私有派生的类

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

请注意,myvector 类限制了对 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);

会发生什么? myvectorbasevector,但尝试在 basevector 中使用公共 indexTo 函数的函数将在 myvector 上失败。

【问题讨论】:

  • 你试过了吗?
  • 不,我没有尝试过,它只是在讲座中出现的。如果 do_something 函数是 myvector 内部的私有函数,它如何访问 indexAt 成员函数?
  • 它只能看到基类,除非你的基类有虚方法,否则它会调用基类中的方法。它并不关心基类是否被派生类私有扩展。

标签: c++ class inheritance private


【解决方案1】:

欢迎使用虚函数!每当您将类中的函数标记为virtual 时,您就是在告诉编译器,“嘿,我可能稍后会覆盖这个函数。如果我这样做了,那么请确保使用新的覆盖版本!”。它与限制对类中函数的访问无关。这就是 public 关键字的作用。

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

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

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

好的。那又怎样?

好吧,当您定义一个采用通用basevector 的新函数时,例如do_something,编译器知道basevector 具有虚函数。每当它调用其中一个函数时,它都必须查看在创建basevector 时生成的表。在您的示例中,该表是来自myvector 的表。因此,do_something 将调用basevectorindexTo,无论您传入的是basevector 还是myvector

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

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

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

但是,当涉及到私有继承时,您应该将其视为以下内容:

class A : private B { ... 

这意味着“A 在 B 中可以访问的所有内容对于 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 的基类!既然我们知道它是,我们可以转换指针 到basevector 并引发相同的行为,因为我们知道虚函数是如何工作的。

【讨论】:

    【解决方案2】:

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

    本质上,私有继承类似于秘密继承——子类从基类继承这一事实在外部是不可见的。所以,编译器甚至不会让你做你写的:

    basevector * ptr = nullptr;
    ptr = new myvector;
    

    因为私有继承的规则。

    【讨论】:

      【解决方案3】:

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

      Cannot convert 'myvector *' to 'basevector *'
      

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

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

      【讨论】:

        猜你喜欢
        • 2017-07-18
        • 1970-01-01
        • 2014-04-27
        • 2022-01-03
        • 1970-01-01
        • 2015-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多