这出现在我的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);
会发生什么? myvector
是basevector
,但尝试使用indexTo
中的公开basevector
功能的功能将在myvector
上失败。
答案 0 :(得分:2)
理论上,函数不应该关心子类或它是如何从基类继承的,所以假设你有这样的指针,是的,函数会正常运行它。但实际上,答案是否定的,因为基类指向私有继承{child}的子类实例。
本质上,私有继承就像秘密继承一样 - 子类从基类继承的事实不是外部可见的。所以,编译器甚至不会让你做你写的:
basevector * ptr = nullptr;
ptr = new myvector;
由于私有继承的规则。
答案 1 :(得分:1)
欢迎使用虚拟功能!每当你在类中标记一个函数virtual
时,你告诉编译器,“嘿,我可能会在以后覆盖这个函数。如果我这样做,那么一定要使用新的重写版本!”。它与限制对类中函数的访问无关。这就是public
关键字的作用。
在您的具体示例中,您可以同时访问basevector
和myvector
中的所有四项功能。但是,这些函数表示的内容取决于您正在使用的值的类型(而不是指针的类型!)当您创建new myvector
时,您还创建了一个指向函数的表它应该使用:
push --> myvector::push
pop --> myvector::pop
getSize --> myvector::getSize
indexTo --> basevector::indexTo
最后一个是自动发生的,因为您在声明basevector
时继承了myvector
。在您对myvector
的定义中,您已经覆盖了其他三个。
行。那是什么?
好吧,当你定义一个带有泛型basevector
的新函数时,如do_something
,编译器知道basevector
有虚函数。每当它调用其中一个函数时,它必须查看创建basevector
时生成的表。在您的示例中,该表是myvector
中的表。因此,无论您是否传递了do_something
或basevector
,indexTo
都会调用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}}。