通过指向派生函数的指针调用基虚方法 class
Call base virtual method by pointer to function from derived class
我需要通过指针从派生 class 调用基方法 A::foo()。
#include <iostream>
struct A{
virtual void foo() { std::cout << "A::foo()" << std::endl; }
};
struct B:A{
virtual void foo() { std::cout << "B::foo()" << std::endl; }
void callBase(void (A::*f)()){
(this->*f)();
}
};
int main(){
B* p=new B();
p->callBase(&A::foo);
}
这段代码输出"B::foo"。是否可以通过指向方法的指针调用 A::foo() ?
好吧,您可以使用一些技巧来覆盖 this
的值来做类似的事情。不过,您可能永远不应该尝试这样做,vtable
指针不应该被手动修改。
要执行您描述的操作,我们需要有指向 A 的 vtable
的指针。我们的对象 p
只有指向 B 的 vtable
的指针,因此我们需要将第二个指针存储在 A 的构造函数中的字段中。
代码如下:
#include <iostream>
struct A{
virtual void foo() { std::cout << "A::foo()" << std::endl; }
int *a_vtable_ptr;
// First, save value of A's vtable pointer in a separate variable.
A() { a_vtable_ptr = *(int**)this; }
};
struct B:A{
virtual void foo() { std::cout << "B::foo()" << std::endl; }
void callBase(void (A::*f)()){
int *my_vtable_ptr = *(int**)this;
// Then modify vtable pointer of given object to one that corresponds to class A.
*(int**)this = a_vtable_ptr;
(this->*f)(); // Call the method as usual.
// Restore the original vtable pointer.
*(int**)this = my_vtable_ptr;
}
};
// Function main() is not modified.
int main(){
B* p=new B();
void (A::*f)() = &A::foo;
p->callBase(f);
}
输出:
A::foo()
Process finished with exit code 0
虚方法旨在实现多态性,指向虚方法的指针支持它们的多态行为。但是您可以通过显式调用 p->A::foo()
.
来调用基本方法
所以如果你想通过指针调用基方法,你应该使它成为非虚拟的(如评论中提到的@PasserBy)。
代码示例:
struct A {
virtual void foo() { std::cout << "A::foo()" << std::endl; }
void bar() { std::cout << "A::bar()" << std::endl; }
void callBase(void (A::*f)()) { (this->*f)(); }
};
struct B : A {
virtual void foo() { std::cout << "B::foo()" << std::endl; }
void bar() { std::cout << "B::bar()" << std::endl; }
};
int main()
{
A* p = new B();
p->foo();
p->bar();
p->callBase(&A::foo);
p->callBase(&A::bar);
p->A::foo();
p->A::bar();
}
输出:
B::foo()
A::bar()
B::foo()
A::bar()
A::foo()
A::bar()
我需要通过指针从派生 class 调用基方法 A::foo()。
#include <iostream>
struct A{
virtual void foo() { std::cout << "A::foo()" << std::endl; }
};
struct B:A{
virtual void foo() { std::cout << "B::foo()" << std::endl; }
void callBase(void (A::*f)()){
(this->*f)();
}
};
int main(){
B* p=new B();
p->callBase(&A::foo);
}
这段代码输出"B::foo"。是否可以通过指向方法的指针调用 A::foo() ?
好吧,您可以使用一些技巧来覆盖 this
的值来做类似的事情。不过,您可能永远不应该尝试这样做,vtable
指针不应该被手动修改。
要执行您描述的操作,我们需要有指向 A 的 vtable
的指针。我们的对象 p
只有指向 B 的 vtable
的指针,因此我们需要将第二个指针存储在 A 的构造函数中的字段中。
代码如下:
#include <iostream>
struct A{
virtual void foo() { std::cout << "A::foo()" << std::endl; }
int *a_vtable_ptr;
// First, save value of A's vtable pointer in a separate variable.
A() { a_vtable_ptr = *(int**)this; }
};
struct B:A{
virtual void foo() { std::cout << "B::foo()" << std::endl; }
void callBase(void (A::*f)()){
int *my_vtable_ptr = *(int**)this;
// Then modify vtable pointer of given object to one that corresponds to class A.
*(int**)this = a_vtable_ptr;
(this->*f)(); // Call the method as usual.
// Restore the original vtable pointer.
*(int**)this = my_vtable_ptr;
}
};
// Function main() is not modified.
int main(){
B* p=new B();
void (A::*f)() = &A::foo;
p->callBase(f);
}
输出:
A::foo()
Process finished with exit code 0
虚方法旨在实现多态性,指向虚方法的指针支持它们的多态行为。但是您可以通过显式调用 p->A::foo()
.
所以如果你想通过指针调用基方法,你应该使它成为非虚拟的(如评论中提到的@PasserBy)。
代码示例:
struct A {
virtual void foo() { std::cout << "A::foo()" << std::endl; }
void bar() { std::cout << "A::bar()" << std::endl; }
void callBase(void (A::*f)()) { (this->*f)(); }
};
struct B : A {
virtual void foo() { std::cout << "B::foo()" << std::endl; }
void bar() { std::cout << "B::bar()" << std::endl; }
};
int main()
{
A* p = new B();
p->foo();
p->bar();
p->callBase(&A::foo);
p->callBase(&A::bar);
p->A::foo();
p->A::bar();
}
输出:
B::foo()
A::bar()
B::foo()
A::bar()
A::foo()
A::bar()