采用指向基类的指针的函数是否也接受从基类私有派生的子类?

时间:2015-04-07 00:41:21

标签: c++ class inheritance private

这出现在我的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,但尝试使用indexTo中的公开basevector功能的功能将在myvector上失败。

3 个答案:

答案 0 :(得分:2)

理论上,函数不应该关心子类或它是如何从基类继承的,所以假设你有这样的指针,是的,函数会正常运行它。但实际上,答案是否定的,因为基类指向私有继承{child}的子类实例。

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

basevector * ptr = nullptr;
ptr = new myvector;

由于私有继承的规则。

答案 1 :(得分:1)

欢迎使用虚拟功能!每当你在类中标记一个函数virtual时,你告诉编译器,“嘿,我可能会在以后覆盖这个函数。如果我这样做,那么一定要使用新的重写版本!”。它与限制对类中函数的访问无关。这就是public关键字的作用。

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

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

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

行。那是什么?

好吧,当你定义一个带有泛型basevector的新函数时,如do_something,编译器知道basevector有虚函数。每当它调用其中一个函数时,它必须查看创建basevector时生成的表。在您的示例中,该表是myvector中的表。因此,无论您是否传递了do_somethingbasevectorindexTo都会调用basevector的{​​{1}}。

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

indexTo

现在,如果您尝试创建class basevector { public: virtual int indexTo(int arg) = 0; /* ... */ }; ,编译器会抱怨它无法找到指向其虚拟函数表中new myvector条目的内容(通常称为“V” -table“)。

但是,在私有继承方面,您应该将其视为以下内容:

indexTo

这意味着“A在A中可以访问的所有内容对A以外的人都是私有的”。所以稍后,您可以执行以下操作:

class A : private B { ... 

但是,如this question中所述,使用私有继承隐藏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(); 也是basevector的基类!既然我们知道它,我们可以投射指针 到myvector并引出相同的行为,因为我们知道虚函数是如何工作的。

答案 2 :(得分:1)

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

Cannot convert 'myvector *' to 'basevector *'

只要您将private更改为public继承,就可以正常使用。

但是,假设您可以myvector*分配给basevector*indexAt()中的public被声明为basevector,而do_something()正在basevector直接访问indexAt(),因此可以访问{{1}}。