接受指向基 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
关键字的作用。
在您的具体示例中,您可以从 basevector
和 myvector
访问所有四个函数。但是,这些函数代表什么取决于您使用的值的类型(而不是指针的类型!)当您创建一个 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。因此,无论您是否传入 basevector
或 myvector
.
,do_something
都会调用 basevector
的 indexTo
你实际上可以强制 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;
因为私有继承规则。
这是在我的 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
关键字的作用。
在您的具体示例中,您可以从 basevector
和 myvector
访问所有四个函数。但是,这些函数代表什么取决于您使用的值的类型(而不是指针的类型!)当您创建一个 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。因此,无论您是否传入 basevector
或 myvector
.
do_something
都会调用 basevector
的 indexTo
你实际上可以强制 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;
因为私有继承规则。