我写了一些代码,但我无法编译它:
#include <cstdio>
#include <vector>
using namespace std;
class Visitor;
class Land {
public:
virtual void accept(const Visitor *v);
};
class England : public Land {
public:
void accept(const Visitor *v);
};
class Russia : public Land {
public:
void accept(const Visitor *v);
};
class Visitor {
public:
void visit(const England *e) const;
void visit(const Russia *r) const;
};
class Trip {
private:
vector<Land> *l;
public:
explicit Trip(vector<Land> *_l);
void accept(Visitor *v);
};
/**/
void Visitor::visit(const England *e) const { … 在以下代码中:
#include <iostream>
using namespace std;
class A {
public:
A() {
cout << " A constructor \n";
sum(2,4);
}
virtual int sum(int a, int b){
cout << "Base sum \n";
return a + b;
}
};
class B : public A {
public:
B() : A() {
cout << " B constructor \n";
}
int sum(int a, int b){
cout << "Overloaded sum \n";
return (a + b) * 10;
}
};
int main(){
A* a = …Run Code Online (Sandbox Code Playgroud) 这是在一次采访中向我提出的问题.
如果Vtable是在编译时创建的,并且vptr在运行时被分配给对象,那么如果我们的类中有虚拟构造函数,那么为什么编译器会给出编译时错误?
我解释了整个机制.但是他对' 为什么编译时错误而不是运行时错误 ' 更感兴趣
我告诉他,C++指南是用来编写的,因此编译器会在编译时发送错误.
能否请你告诉我同样的原因
我在C++中有两个类:
class Base
{
int baseField;
public:
Base();
~Base();
T BaseMethod();
virtual SomeMethod()=0;
};
class Derived : public Base
{
int derivedField;
public:
Derived()
~Derived();
T DerivedMethod();
virtual SomeMethod() {...}; // Some implementation
};
Run Code Online (Sandbox Code Playgroud)
我的问题是它是如何在内存中表示的,即这个类的指针,vptr(vtable)字段和方法指针在哪里.好的,它依赖于编译器,但有一些不成文的标准.我对Visual Studio和gcc编译器最感兴趣.
[编辑:我用一个虚拟方法来改进示例,之前没有任何虚拟]
有没有一些关于这个主题的书籍
我正在为学校做一个项目,但遇到了一个我不知道如何解决的问题。以下是部分代码(不是整个类)和错误消息:
class CCPU
{
public:
CCPU ( uint8_t * memStart,
uint32_t pageTableRoot );
virtual ~CCPU ( void ) { }
virtual uint32_t GetMemLimit ( void ) const = 0;
virtual bool SetMemLimit ( uint32_t pages ) = 0;
virtual bool NewProcess ( void * processArg,
void (* entryPoint) ( CCPU *, void * ),
bool copyMem ) = 0;
bool ReadInt ( uint32_t address,
uint32_t & value );
bool WriteInt ( uint32_t address,
m_PageTableRoot;
};
Run Code Online (Sandbox Code Playgroud)
这是从上面继承的类:
class CProcManager : public …Run Code Online (Sandbox Code Playgroud) 所以我知道在 C++ 中,虚拟方法适用于存储在表中的每个类,并且每个实例都有一个指向该表的指针。所以我的问题是子类表是什么样的。我将提供一个汇编指令:
vtable for Derived:
.long 0
.long _typeinfo for Derived
.long _Derived::set()
.globl _vtable for Base
.section .rdata$vtable for Base,"dr"
.linkonce same_size
.align 4
Run Code Online (Sandbox Code Playgroud)
因此,从这里我可以看到 Derived 有一个虚拟方法set(),但令我烦恼的部分是 Base 的 vtable。Derived vptr 是否保存指向 Base vptr 的指针,还是存储在 Derived 的 vtable 内。我注意到,在代码中,编译器仅将 vtable 存储在对象的 0 地址处,一次存储在 Base 构造函数中,一次存储在 Derived 中。为什么vtable没有被覆盖?
PS我不太明白指令
编辑:
class Base{
virtual void print() {
printf("Base");
}
}
class Derived : Base{
virtual void print(){
printf("Derived");
}
}
Run Code Online (Sandbox Code Playgroud) 我很难弄清楚为什么我的代码不起作用。我将问题追溯到 vtable 生成/填充。
这是我的代码的简化版本:
#include <iostream>
#include <functional>
#include <thread>
using namespace std;
typedef std::function<void (void)> MyCallback;
MyCallback clb = NULL;
void callCallbackFromThread(void){
while(clb == NULL);
clb();
}
int someLongTask(void){
volatile unsigned int i = 0;
cout << "Start someLongTask" << endl;
while(i < 100000000)
i++;
cout << "End someLongTask" << endl;
return i;
}
class Base{
public:
Base(){
clb = std::bind(&Base::_methodToCall, this);
cout << "Base-Constructor" << endl;
}
protected:
virtual void methodToCall(void){
cout << "Base methodToCall got called!" << …Run Code Online (Sandbox Code Playgroud) 我有一个使用 CRTP 和 C++20 的代码:
template<class Derived>
class Base {
public:
void m() {
static_cast<Derived*>(this)->feature();
}
virtual constexpr void feature() = 0;
}
class BaseImpl: public Base<BaseImpl> {
virtual constexpr void feature() final override { // ... };
}
Run Code Online (Sandbox Code Playgroud)
有没有办法删除vptr,这样对象就不会占用 8 个字节(对于 x64),而只占用 1 个字节?(因为它从不使用运行时多态性)?
在实际代码中,层次结构要复杂得多,有 2 个vptr(因此需要 16 个字节)。是否有类似 GCC 或 MSVC 的扩展?
是的,当然,解决方案之一就是删除该virtual方法。但由于它具有复杂的层次结构,它带来了极其丑陋的错误和不可维护的代码,因为程序员应该通过读取不可读的模板实例化错误来猜测必须实现哪些方法。
整个目标是实现类似 Java 的层次结构(具有接口、覆盖检查等),但具有零成本抽象。
我做了一些实验(探索代码反汇编),编译器完全优化了所有虚拟调用,提供了零成本抽象。除了它将对象扩展为具有vptr我的代码中从未使用过的 a 。
我发现了类似的东西__declspec(novtable),但vptr仍然占用空间。是的,物体的尺寸尽可能小是极其重要的。
为什么只有默认构造函数才能创建vptr(虚拟表指针)和vtable(虚拟表)?为什么参数构造函数不能
c++ ×9
vtable ×9
constructor ×3
inheritance ×2
vptr ×2
assembly ×1
crtp ×1
linker ×1
methods ×1
oop ×1
polymorphism ×1
this ×1
virtual ×1