我想知道使用一个不允许多重继承的编译器编译类A的后果是什么,并编译一个支持它的类B(以及从类A派生的类B).
我真的不明白链接过程......是否可以同时使用它们?在这种情况下使用单独的编译器有什么不利之处?使用B类的代码是否无法正常运行?
谢谢.
我对C++和虚拟继承感到好奇 - 特别是在低音和子类之间解决vtable冲突的方式.我不会假装了解它们如何工作的具体细节,但到目前为止我发现的是由于该分辨率使用虚拟函数导致的延迟很小.我的问题是基类是否为空 - 即,其虚函数定义为:
virtual void doStuff() = 0;
Run Code Online (Sandbox Code Playgroud)
这是否意味着分辨率不是必需的,因为只有一组函数可供选择?
如果这是一个愚蠢的问题,请原谅我 - 正如我所说的,我不明白vtable是如何运作的,所以我真的不知道更好.
编辑
所以,如果我有一个带有两个单独子类的抽象类:
A
/ \
/ \
B C
Run Code Online (Sandbox Code Playgroud)
从子类调用函数时,没有性能损失,比如说,只有一个继承自由类?
Clang自己的诊断宣传包含以下内容:
由于Clang具有范围突出显示功能,因此您无需再将代码打印出来.这在G ++中尤其糟糕(它经常发出包含降低的vtable引用的错误),但是在某些情况下,即使GCC在尝试执行此操作时也会产生难以理解的错误消息.
谷歌搜索这个短语并没有给出任何非常有用的信息,后续的例子完全不相关.
有人可以发一个它正在谈论的例子吗?
谢谢.
以这两个类为例.(C++)
class B1 {
public:
};
class B2 {
public:
void f0 () {}
void f1 () {}
};
Run Code Online (Sandbox Code Playgroud)
B2类在内存中与B1相比会有多大
我觉得这是两个答案中的一个.
32位系统PER方法上的单个4字节int指针.
或类似于虚拟方法表http://en.wikipedia.org/wiki/Virtual_method_table所发生的事情
哪里会有一个4字节的int指针指向每个类的表,所以它可以查找它的方法,这是有道理的,但我不知道这是否适用于非虚方法.
谢谢.
编辑:感谢所有的精彩和快速回复:)(也标记答案)
C中实现"面向对象"的一种常见做法是使用函数指针数组.这似乎与C++ vtable类似,实质上C++虚函数机制只是函数指针数组的语法糖.
但是C机制还有一个在C++中缺少的附加功能.函数指针可以为NULL,调用者可以检查函数是否为NULL,以查看对象是否实现某种方法.但是在C++中,方法不能为NULL,并且类不能"不实现"方法.
在C++中模仿这种行为的最接近的方法是什么?
为了实现动态绑定,对于每个类,都有一个虚拟表来存储每个函数的addr.为什么需要这种间接?我们可以让类直接将ptr存储到正确的函数中吗?
我试图使用抽象类来表示子类型的公共基础.但是,无论我做什么,它(看起来像是链接器)都会对vtable和未定义的引用保持呻吟.根据错误消息判断,问题必须以某种方式与析构函数相关.Wierdldy足够,它一直在谈论一个
"未定义引用'AbstractBase :: ~AbstractBase()'"
在child.cpp中没有任何意义.
就像上次一样,我实际上无法显示我的代码,所以这里有一个实际上做同样事情的例子:
首先是抽象类"AbstractBase.h":
#ifndef ABSTRACTBASE
#define ABSTRACTBASE
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
}
#endif
Run Code Online (Sandbox Code Playgroud)
使用abstractbase的子节点"child.h":
#ifndef CHILD
#define CHILD
class child : public AbstractBase
{
public:
~child() override;
}
#endif
Run Code Online (Sandbox Code Playgroud)
"child.cpp"中的实现:
#include "child.h"
child::~child()
Run Code Online (Sandbox Code Playgroud)
显然有更多的功能,但实质上这就是我的真正的类的析构函数的外观.
在网上搜索了在C++中使用抽象类的方法之后,我即将放弃.据我从这些消息来源可以看出,这是做到这一点的方法.您声明您的摘要类的析构函数是虚拟的,因此对它的任何调用都将包含该子项.孩子的析构函数只是标记为覆盖.它应该没有任何其他东西.
我错过了一些真正重要的东西吗?
PS:加入MCVE:
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
};
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
~child() override
{}
}
int main (argc, char *argv[])
{
child* ptr = new …Run Code Online (Sandbox Code Playgroud) 我将Base类更改为抽象(即我将其中一个方法设为纯虚拟)并重新编译它.当我将它与派生类链接时,链接器抱怨了vtable.我用nm调查了一些事情,但我不确定nm告诉我的是什么.我只是通过删除*.o文件并重新编译Derived类来解决问题,但我想了解这里的vtable究竟发生了什么.
我的原始代码是这样的:
Base.h
class Base {
public:
virtual void doSomething();
};
Run Code Online (Sandbox Code Playgroud)
Base.cpp
#include <iostream>
#include <Base.h>
void Base::doSomething() {
std::cout << "Base::doSomething()" << "\n";
}
Run Code Online (Sandbox Code Playgroud)
Derived.h
#include <Base.h>
class Derived : public Base {
public:
Derived();
void doSomething() override;
};
Run Code Online (Sandbox Code Playgroud)
Derived.cpp
#include <iostream>
#include <Derived.h>
Derived::Derived() {
std::cout << "Derived::Derived() constructor" << "\n";
}
void Derived::doSomething() {
std::cout << "Derived::doSomething()" << "\n";
}
Run Code Online (Sandbox Code Playgroud)
Makefile包含以下内容:
CXXFLAGS = -std=c++14 -pedantic -Wall -Werror -I ./
default: build
clean:
rm -f proggy
rm -f …Run Code Online (Sandbox Code Playgroud) 在下面的示例中,Type具有虚拟方法,因此具有vtable。但是,Type :: Bar()不是虚拟的。调用Bar()时,该调用是否还会通过vtable机制执行,还是仅适用于Foo()?
struct Base {
virtual void Foo() {}
}
struct Type : Base {
void Foo() override {}
void Bar() {}
}
Base* b = new Type();
Type* t = static_cast<Type*>(b);
t->Bar(); // Does this use a vtable?
Run Code Online (Sandbox Code Playgroud) 我试图了解一个类的vtable在C ++中的敏感程度,为此,我需要知道对于下面列出的3个更改方案是否需要重新编译整个类层次结构(总共3个头文件)。首先,这是我的班级层次结构:
class A {
public:
virtual void method1() = 0;
virtual void method2() = 0;
virtual ~A() {}
};
class B : public A {
public:
virtual void method1() {};
virtual void method2() {};
virtual ~B() {}
};
class C : public A {
public:
virtual void method1() {};
virtual void method2() {};
virtual ~C() {}
};
Run Code Online (Sandbox Code Playgroud)
这是我的情况:
非虚拟方法被添加到基类A:
void method3() {};
Run Code Online (Sandbox Code Playgroud)具有主体的虚拟方法被添加到基类A中:
virtual void method3() {};
Run Code Online (Sandbox Code Playgroud)将纯虚拟方法添加到基类A:
virtual void method3() = 0;
Run Code Online (Sandbox Code Playgroud)在方案1中,不对vtable进行任何更改。是否仍然需要重新编译B和C?
在方案2中,是否会针对基数A并因此针对B和C重构vtable?
我知道方案3将强制类B和C提供新方法的实现。因此,必须重新编译整个层次结构。