当我尝试访问从虚拟基类继承的派生类对象的内存布局时,出了点问题.
编程环境:GNU/Linux 3.19.0-32-generic,x86_64
编译器:gcc 4.8.4
//virtual base class
class Base {
public :
virtual void f() {
cout << "Base::f()" << endl;
}
private:
long x;
};
//derived class
class Derived : public virtual Base {
public:
virtual void f() {
cout << "Derived::f()" << endl;
}
private:
long y;
};
int main() {
typedef void (*FUNC)(void);
Derived d;
//In my machine, sizeof(long) == sizeof(pointers). My code below is neither portable nor concise. You can just read the annotation.
//dereference …Run Code Online (Sandbox Code Playgroud) 为什么打印20000?代码在继承序列中一直显式调用特定的基础构造函数,但忽略指定的构造函数并使用默认构造函数.
#include <iostream>
struct Car
{
Car() : price(20000) {}
Car(double b) : price(b*1.1) {}
double price;
};
struct Toyota : public virtual Car
{
Toyota(double b) : Car(b) {}
};
struct Prius : public Toyota
{
Prius(double b) : Toyota(b) {}
};
int main(int argc, char** argv)
{
Prius p(30000);
std::cout << p.price << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud) 在这个例子中我对多态性的应用有些麻烦.这个问题类似于我的上一个问题
有3个抽象类:
class A
{
public:
virtual A * copy () const = 0;
virtual ~A() = 0;
};
A::~A(){}
class B
{
public:
virtual B * copy () const = 0;
virtual ~B() = 0;
};
B::~B(){}
class C: virtual public A , public B
{
public:
virtual C * copy () const = 0;
virtual ~C() = 0;
};
C::~C(){}
Run Code Online (Sandbox Code Playgroud)
和两个使用虚拟继承的继承类
class D: virtual public A
{
public:
virtual D * copy () const {return new D …Run Code Online (Sandbox Code Playgroud) c++ covariance virtual-inheritance visual-c++ visual-c++-2010
#include<iostream>
using namespace std;
class abc
{
int a;
};
class xyz : public virtual abc
{
int b;
};
int main()
{
abc obj;
xyz obj1;
cout<<endl<<sizeof(obj);
cout<<endl<<sizeof(obj1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
答案将取决于编译器,但当我看到这个结果时,我感到很惊讶
~/Documents/workspace/tmp ‹.rvm-› $ ./class_sizes
4
16
Run Code Online (Sandbox Code Playgroud)
如果我删除虚拟关键字,那么分配的大小分别为4和8,这正是我的预期.
为什么额外的空间被准确占用?我怀疑它是针对vptr表或其他类似但不确定的.
当我尝试编译以下代码时:
class A {
public:
A(int v) : virt(v) { }
int virt;
int getVirt(void) const { return virt; }
};
class B : private virtual A {
protected:
B(int v) : A(v) { }
using A::getVirt;
};
class C : public B, private virtual A {
protected:
C(int v) : A(v), B(v) { }
using A::getVirt;
};
class D : public C {
public:
D(void) : C(3) { }
using C::getVirt;
};
#include <iostream>
int main(int argc, char *argv[]) …Run Code Online (Sandbox Code Playgroud) 因此,使用static_cast虚拟继承进行向下转换是不可能的,但是如何进行以下向上转换:
class Base {...};
class Derived : public virtual Base {...};
...
Derived *d = new Derived();
Base *b = static_cast<Base*>(d);
Run Code Online (Sandbox Code Playgroud)
对象的内存布局:
[ derived part | base part ]
Run Code Online (Sandbox Code Playgroud)
我知道向上转换被认为是"安全的",但是当继承是虚拟的时,编译器如何知道编译时对基础子对象的偏移?是否static_cast使用vtable?
当我们有这样的事情时,这尤其令人困惑(注意它不是虚拟的):
class Third : public Derived {...};
...
Derived *d = new Third(); // non-virtual upcast, no offset will be added
Base *b = static_cast<Base*>(d);
Run Code Online (Sandbox Code Playgroud)
这次我使用相同的static_cast线,但Base子对象的偏移量是不同的!
对象的内存布局:
[ derived part | third part | base part ]
Run Code Online (Sandbox Code Playgroud)
那么如何在编译时确定它是否取决于对象的实际动态类型d指向?
我有三个类这样的结构:
#include <iostream>
using namespace std;
class Keyword
{
public:
virtual float GetValue() = 0;
};
class CharacterKeyword : public Keyword
{
public:
virtual float GetValue(){return _value;}
private:
float _value;
};
class MeasurementKeyword : public Keyword
{
public:
virtual float GetValue(){return _value;}
private:
float _value;
};
class AddressType : public CharacterKeyword, public MeasurementKeyword
{
private:
float address;
float addresExt;
};
int main()
{
AddressType *a = new AddressType();
a->GetValue();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到以下内容:
In function ‘int main()’:
error: request for …
我即将创建一个异常类层次结构,概念上看起来像这样:
#include <iostream>
#include <stdexcept>
class ExceptionBase : public std::runtime_error {
public:
ExceptionBase( const char * msg ) : std::runtime_error(msg) {}
};
class OperationFailure : virtual public ExceptionBase {
public:
using ExceptionBase::ExceptionBase;
};
class FileDoesNotExistError : virtual public ExceptionBase {
public:
using ExceptionBase::ExceptionBase;
};
class OperationFailedBecauseFileDoesNotExistError
: public OperationFailure, FileDoesNotExistError {
public:
using ExceptionBase::ExceptionBase; // does not compile
};
int main() {
OperationFailedBecauseFileDoesNotExistError e("Hello world!\n");
std::cout << e.what();
}
Run Code Online (Sandbox Code Playgroud)
所有构造函数应该与ExceptionBase类的构造函数相同.派生的异常仅在类型上有所不同,否则没有添加的功能.上面代码中提到的最后一个异常类型也应该有这些构造函数.这是否可以使用C++ 11标准的继承构造函数功能?如果那是不可能的:还有什么选择?
(顺便说一句:在上面的代码中的类OperationFailure和FileDoesNotExistError.没有用gcc 4.8编译,但铿锵3.4显然,海湾合作委员会拒绝为虚拟基础继承构造函数这将是有趣的,知道谁在这里两种编译器拒绝了类OperationFailedBecauseFileDoesNotExistError …
在以下代码中,编译器请求基类X是默认可构造的.但是,如果我删除虚拟从继承关键字类节点,接入到成员m_x变,当然,暧昧的,但默认构造函数的类X不再需要.
这是什么原因?
#include <iostream>
struct Apply
{
template< typename T >
struct Node : virtual T // this line contains the virtual inheritance
{
template< typename ...Args>
Node( Args... args )
: T( args... )
{}
};
template < typename ...BaseClasses>
struct Inheritance;
template < typename FirstBaseClass, typename ...OtherBaseClasses>
struct Inheritance< FirstBaseClass, OtherBaseClasses... > : FirstBaseClass
, Inheritance< OtherBaseClasses... >
{
template< typename ...Args>
Inheritance( Args... …Run Code Online (Sandbox Code Playgroud) c++ virtual-inheritance default-constructor template-meta-programming variadic-templates
以下显然有效的代码使用UndefinedBehaviorSanitizer sanitiser产生错位的地址运行时错误.
#include <memory>
#include <functional>
struct A{
std::function<void()> data; // seems to occur only if data is a std::function
} ;
struct B{
char data; // occurs only if B contains a member variable
};
struct C:public virtual A,public B{
};
struct D:public virtual C{
};
void test(){
std::make_shared<D>();
}
int main(){
test();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在macbook上编译和执行
clang++ -fsanitize=undefined --std=c++11 ./test.cpp && ./a.out
产生输出
runtime error: constructor call on misaligned address 0x7fe584500028 for type 'C', which requires 16 byte …
c++ ×10
c++11 ×2
abi ×1
clang++ ×1
constructor ×1
covariance ×1
g++ ×1
inheritance ×1
oop ×1
sanitizer ×1
static-cast ×1
visual-c++ ×1
vtable ×1