我正在尝试打印虚拟成员函数的地址.如果我知道哪个类实现了我可以编写的函数:
print("address: %p", &A::func);
Run Code Online (Sandbox Code Playgroud)
但我想做这样的事情:
A *b = new B();
printf("address: %p", &b->func);
printf("address: %p", &b->A::func);
Run Code Online (Sandbox Code Playgroud)
但是这不会编译.是否有可能做这样的事情,也许在运行时查找vtable中的地址?
最近遇到了一个对我来说很新的C++链接器错误.
libfoo.so: undefined reference to `VTT for Foo'
libfoo.so: undefined reference to `vtable for Foo'
Run Code Online (Sandbox Code Playgroud)
我认识到这个错误并解决了我的问题,但我还有一个唠叨的问题:什么是VTT?
旁白:对于那些感兴趣的人,当您忘记定义类中声明的第一个虚函数时,会出现问题.vtable进入类的第一个虚函数的编译单元.如果你忘了定义那个函数,你会得到一个链接器错误,它无法找到vtable而不是更加开发人员友好的找不到该函数.
档案啊
#ifndef A_H_
#define A_H_
class A {
public:
virtual ~A();
virtual void doWork();
};
#endif
Run Code Online (Sandbox Code Playgroud)
文件Child.h
#ifndef CHILD_H_
#define CHILD_H_
#include "A.h"
class Child: public A {
private:
int x,y;
public:
Child();
~Child();
void doWork();
};
#endif
Run Code Online (Sandbox Code Playgroud)
和Child.cpp
#include "Child.h"
Child::Child(){
x = 5;
}
Child::~Child(){...}
void Child::doWork(){...};
Run Code Online (Sandbox Code Playgroud)
编译器说对vtable有一个未定义的引用A.我尝试了很多不同的东西,但没有一个有效.
我的目标是将类A作为接口,并从头部分离实现代码.
n3797说:
§7.1.6.4/14:
使用占位符类型的返回类型声明的函数不应是虚拟的(10.3).
因此,以下程序格式错误:
struct s
{
virtual auto foo()
{
}
};
Run Code Online (Sandbox Code Playgroud)
虚拟
允许对虚函数进行返回类型推导是可能的,但这会使重写检查和vtable布局复杂化,因此似乎最好禁止这种情况.
任何人都可以提供进一步的理由或给出一个与上述引用一致的好(代码)示例吗?
什么时候编译器创建一个虚函数表?
1)当类包含至少一个虚函数时.
要么
2)当直接基类包含至少一个虚函数时.
要么
3)当层次结构的任何级别的任何父类包含至少一个虚函数时.
与此相关的问题:是否可以放弃C++层次结构中的动态调度?
例如,考虑以下示例.
#include <iostream>
using namespace std;
class A {
public:
virtual void f();
};
class B: public A {
public:
void f();
};
class C: public B {
public:
void f();
};
Run Code Online (Sandbox Code Playgroud)
哪些类将包含V表?
既然B没有将f()声明为虚拟,那么C类是否会获得动态多态性?
我正在评估将一个实时软件从C /汇编语言重写为C++ /汇编语言(由于与代码问题无关的原因,在汇编时绝对需要这样做).
中断带有3 kHz频率,对于每个中断,大约200个不同的事情将按顺序完成.处理器以300 MHz运行,为我们提供100,000个周期来完成这项工作.这已在C中用函数指针数组求解:
// Each function does a different thing, all take one parameter being a pointer
// to a struct, each struct also being different.
void (*todolist[200])(void *parameters);
// Array of pointers to structs containing each function's parameters.
void *paramlist[200];
void realtime(void)
{
int i;
for (i = 0; i < 200; i++)
(*todolist[i])(paramlist[i]);
}
Run Code Online (Sandbox Code Playgroud)
速度很重要.上述200次迭代每秒完成3000次,因此实际上我们每秒进行600,000次迭代.上面的for循环每次迭代编译为五个周期,总成本为每秒3,000,000个周期,即1%的CPU负载.汇编程序优化可能会将其降低到四个指令,但是我担心由于内存访问彼此接近等原因,我们可能会得到一些额外的延迟.简而言之,我相信这五个周期非常理想.
现在进行C++重写.我们做的那200件事情彼此有关.有一个参数的子集,它们都需要和使用,并具有各自的结构.在C++实现中,它们可以被巧妙地视为从公共基类继承:
class Base
{
virtual void Execute();
int something_all_things_need;
}
class Derived1 : Base
{
void Execute() { …Run Code Online (Sandbox Code Playgroud) 因此,vtable是由编译器维护的表,其中包含指向该类中的虚函数的函数指针.
和
将派生类的对象分配给祖先类的对象称为向上转换.
向上转换使用基类指针或引用处理派生类实例/对象; 对象不是"赋值给",这意味着覆盖值ala operator = invocation.
(感谢:Tony D)
现在,如何在运行时知道"哪个"类的虚函数应该被调用?
vtable中的哪个条目指的是应该在运行时调用的"特定"派生类的功能?
虚拟函数如何在C#和Java中工作?
它是否使用与C++类似的相同vtable和vpointer概念,还是完全不同的东西?
我读了很多人写的"一个虚拟表存在于一个已经在其中声明了虚函数的类".
我的问题是,vtable是仅存在于具有虚函数的类还是存在于从该类派生的类中.
例如
class Base{
public:
virtual void print(){cout<<"Base Print\n";}
};
class Derived:public Base{
public:
void print(){cout<<"Derived print\n";}
};
//From main.cpp
Base* b = new Derived;
b->print();
Run Code Online (Sandbox Code Playgroud)
问题:如果没有派生类的vtable,那么输出就不会是"派生打印".所以IMO存在一个vtable,用于任何已声明虚函数的类,也存在于从该类继承的类中.它是否正确 ?