我们都知道C++中的虚函数是什么,但它们是如何在深层次实现的?
可以在运行时修改甚至直接访问vtable吗?
vtable是否适用于所有类,或仅适用于至少具有一个虚函数的类?
抽象类对于至少一个条目的函数指针只有一个NULL吗?
有一个虚拟函数会减慢整个班级的速度吗?或者只调用虚拟函数?如果虚拟功能实际被覆盖了,速度是否会受到影响,或者只要它是虚拟的,它就没有效果.
我在Windows 7 Ultimate 32位上使用Qt Creator 2.0.1和Qt 4.7.0(32位).
请考虑以下代码,这是产生错误的最小代码:
class T : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
T() {}
QRectF boundingRect() const {return QRectF();}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget) {}
};
int main()
{
T t;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码片段导致以下链接器错误:
在函数"T"中:
未定义引用`vtable for T'
未定义引用`vtable for T'
在函数`~T'中:
未定义引用`vtable for T'
未定义引用`vtable for T'
如果我注释掉包含的行Q_OBJECT,它编译得很好.我需要信号和插槽,QGraphicsItem所以我需要Q_OBJECT.
代码有什么问题?谢谢.
这是我的标题:
#ifndef BARELYSOCKET_H
#define BARELYSOCKET_H
#include <QObject>
//! The First Draw of the BarelySocket!
class BarelySocket: public QObject
{
Q_OBJECT
public:
BarelySocket();
public slots:
void sendMessage(Message aMessage);
signals:
void reciveMessage(Message aMessage);
private:
// QVector<Message> reciveMessages;
};
#endif // BARELYSOCKET_H
Run Code Online (Sandbox Code Playgroud)
这是我的班级:
#include <QTGui>
#include <QObject>
#include "type.h"
#include "client.h"
#include "server.h"
#include "barelysocket.h"
BarelySocket::BarelySocket()
{
//this->reciveMessages.clear();
qDebug("BarelySocket::BarelySocket()");
}
void BarelySocket::sendMessage(Message aMessage)
{
}
void BarelySocket::reciveMessage(Message aMessage)
{
}
Run Code Online (Sandbox Code Playgroud)
我收到链接器错误:
undefined reference to 'vtable for BarelySocket'
Run Code Online (Sandbox Code Playgroud)
Message是一个复杂的struct …对于此代码:
class B1{
public:
virtual void f1() {}
};
class D : public B1 {
public:
void f1() {}
};
int main () {
B1 *b1 = new B1();
D *d = new D();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译后,我得到的vtable g++ -fdump-class-hierarchy是:
Vtable for B1
B1::_ZTV2B1: 3u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI2B1)
16 B1::f1
Vtable for D
D::_ZTV1D: 3u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI1D)
16 D::f1
Run Code Online (Sandbox Code Playgroud)
我无法理解像(int()(...))0*这样的条目对应的内容.当然它意味着类似,它是一个函数,它返回一个int并获取无限数量的参数,我不明白任何事情.这个函数指针对应哪个函数?你怎么知道的?我是64位机器.
第二个函数指针的末尾有一个地址?对应的对象是谁?
编辑
我使用的编译器是g ++:
g++ -v …Run Code Online (Sandbox Code Playgroud) C++支持通过虚拟机制进行动态绑定.但据我所知,虚拟机制是编译器的实现细节,标准只是指定了在特定场景下应该发生的行为.大多数编译器通过虚拟表和虚拟指针实现虚拟机制.是的,我知道这是如何工作的,所以我的问题不是关于虚拟指针和表的实现细节.我的问题是:
sizeof只有一个虚函数的任何类的将是一个指针(vptr的内部尺寸this)上编译,所以考虑到虚拟PTR和TBL机制本身是编译器实现,将这个说法我在上面做永远是真的吗?几乎是最后一步,但仍然有一些奇怪的错误......
bash-3.2$ make
g++ -Wall -c -g Myworld.cc
g++ -Wall -g solvePlanningProblem.o Position.o AStarNode.o PRM.o PRMNode.o World.o SingleCircleWorld.o Myworld.o RECTANGLE.o CIRCLE.o -o solvePlanningProblem
Undefined symbols:
"vtable for Obstacle", referenced from:
Obstacle::Obstacle()in Myworld.o
"typeinfo for Obstacle", referenced from:
typeinfo for RECTANGLEin RECTANGLE.o
typeinfo for CIRCLEin CIRCLE.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [solvePlanningProblem] Error 1
Run Code Online (Sandbox Code Playgroud)
vtable和typeinfo的含义是什么?
是否有可能没有虚拟方法的继承?编译器说以下代码不是多态的.
例:
Class A(){
int a;
int getA(){return a;};
}
Class B(): A(){
int b;
int getB(){return b;};
}
Run Code Online (Sandbox Code Playgroud)
在另一个类中,我们试图从一个A对象向下转换为一个B对象:
A *a;
B *b = dynamic_cast<B*>(a)
Run Code Online (Sandbox Code Playgroud)
但是这会产生以下错误:
cannot dynamic_cast ... (source type is polymorphic)
Run Code Online (Sandbox Code Playgroud) C++有多重继承.在程序集级别实现多重继承可能非常复杂,但在线上有关于如何正常完成(vtables,指针修正,thunks等)的良好描述.
Java没有多个实现继承,但它确实有多个接口继承,所以我不认为每个类有一个vtable的直接实现可以实现它.java如何在内部实现接口?
我意识到与C++相反,Java是Jit编译的,因此不同的代码片段可能会有不同的优化,不同的JVM可能会做不同的事情.那么,是否存在许多JVM遵循的一般策略,或者有人知道特定JVM中的实现吗?
此外,JVM通常是虚拟化和内联方法调用,在这种情况下根本没有涉及vtable或等效项,因此询问实现虚拟/接口方法调用的实际汇编序列可能没有意义,但我认为大多数JVM仍然保留一些如果类无法将所有内容虚拟化,那么这些类的一般表示形式即可使用.这个假设是错的吗?这种表示形式是否像C++ vtable一样?如果是这样,接口有单独的vtable,它们如何与类vtable链接?如果是这样,对象实例可以有多个vtable指针(对于类/接口vtable),就像C++中的对象实例一样吗?对同一对象的类类型和接口类型的引用是否总是具有相同的二进制值,或者它们是否可以像C++中那样需要指针修复?
(供参考:这个问题提出了类似CLR的相似之处,这篇msdn文章似乎有一个很好的解释,虽然现在可能已经过时了.我找不到任何类似的Java.)
编辑:
takeaway.o: In function `takeaway':
project:145: undefined reference to `vtable for takeaway'
project:145: undefined reference to `vtable for takeaway'
takeaway.o: In function `~takeaway':
project:151: undefined reference to `vtable for takeaway'
project:151: undefined reference to `vtable for takeaway'
takeaway.o: In function `gameCore':
project.h:109: undefined reference to `gameCore<int>::initialData(int)'
collect2: ld returned 1 exit status
make: *** [takeaway] Error 1
Run Code Online (Sandbox Code Playgroud)
我一直从链接器中获取此错误,我知道它与内联函数有关,可以暂时存储vtable.但是这需要我不太确定.我认为这与我如何在takeaway.cpp的启动列表中调用gameCore的构造函数有关
我有一个模板化的类(gameCore.h)和一个继承自gameCore的类(takeaway.cpp)vtable错误被称为3次1)在takeaways构造函数中2)takeaways析构函数3)在gameCores构造函数中
我正在使用G ++这里是代码:(我知道它可能看起来很难读,但我已经标记了错误发生的地方)takeaway.h
#ifndef _TAKEAWAY_H_
#define _TAKEAWAY_H_
#include<map>
#include<cctype>
#include<stack>
#include<map>
#include<iostream>
#include<string>
#include<cstdlib>
#include"gameCore.h"
#include<vector>
using namespace std;
class takeaway : public …Run Code Online (Sandbox Code Playgroud) 我正在尝试打印虚拟成员函数的地址.如果我知道哪个类实现了我可以编写的函数:
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中的地址?
vtable ×10
c++ ×9
polymorphism ×2
qt ×2
gcc ×1
inheritance ×1
interface ×1
internals ×1
java ×1
linker ×1
pure-virtual ×1
qobject ×1
virtual ×1
vptr ×1