我想了解多重继承,这是我的代码:
struct A {
A() {}
static int n;
static int increment() { return ++n; }
};
int A::n = 0;
struct B : public A {};
struct C : public A {};
struct D : public B, C {};
int main() {
D d;
cout<<d.increment()<<endl;
cout<<d.increment()<<endl;
}
Run Code Online (Sandbox Code Playgroud)
这段代码有效.但是,如果我increment()改为非静态,它将失败.
我的问题:
increment(),同时满足静态版本?increment()向B或C 添加另一个函数,编译器也会抱怨,甚至声明为静态.为什么?请考虑以下代码.g ++和clang ++都抱怨(正确地)构造函数A(int)在类中是私有的D.注意,作为A一个虚拟的基类的D,A具有在被初始化MEM-初始化类的D,最派生类,根据在C++ 11§12.6.2/ 7.查看实例.
class A {
public:
A(int i) : x(i) { }
A() : x(1) {}
int x;
};
class B : private virtual A {
protected:
B(int i) : A(i) { } };
class C : public B, private virtual A {
protected:
C(int i) : A(i), B(i) { }
};
class D : public C {
public:
D() : …Run Code Online (Sandbox Code Playgroud) 如果我有类继承关系,如下所示
a
/ \
b c
\ |
| d
\/ \
e f
\ /
g
Run Code Online (Sandbox Code Playgroud)
以下是正确的定义吗?
class A {};
class B: public virtual A {};
class C: public virtual A {};
class D: public C {};
class E: public B, public virtual D {};
class F: public virtual D {};
class G: public E, public F {};
Run Code Online (Sandbox Code Playgroud)
我做了A和D几乎是继承的,因为我假设每个联合类都需要是虚拟的.
另外我不确定C++如何定义上述情况的构造函数顺序.链接 https://isocpp.org/wiki/faq/multiple-inheritance#mi-vi-ctor-order说
要执行的第一个构造函数是层次结构中任何位置的虚拟基类.它们按照它们出现在基类图的深度优先从左到右遍历的顺序执行,其中从左到右指的是基类名称的出现顺序.
完成所有虚拟基类构造函数后,构造顺序通常从基类到派生类.如果您想象编译器在派生类的ctor中做的第一件事就是对其非虚基类的ctors进行隐藏调用(提示:这就是许多编译器实际执行的方式),这些细节最容易理解. .因此,如果D类继承B1和B2的乘法,则B1的构造函数首先执行,然后执行B2的构造函数,然后执行D的构造函数.此规则以递归方式应用; 例如,如果B1继承自B1a和B1b,B2继承自B2a和B2b,则最终顺序为B1a,B1b,B1,B2a,B2b,B2,D.
请注意,B1和B2(或B1a然后B1b)的顺序由基类出现在类的声明中的顺序确定,而不是初始化程序出现在派生类的初始化列表中的顺序.
如果是这样,订单是这样的吗?
A, D, B, C, D, F, G
Run Code Online (Sandbox Code Playgroud)
我不认为D是在C之前构造的.什么是正确的构造函数顺序?
考虑以下类层次结构:
如何确定在C++中对类X的对象调用foo()时将执行哪个方法?
(我正在寻找算法,而不是任何特定情况.)
c++ multiple-inheritance virtual-inheritance method-resolution-order
我对vptr和内存中对象的表示感到困惑,希望你能帮助我更好地理解这个问题.
考虑B从中继承A并定义虚函数f().从我了解到的记忆B类对象的表示是这样的:[ vptr | A | B ]
与vtbl该vptr指向包含B::f().我也明白,从铸造对象B来A什么都不做,除了忽略B在对象的端部.这是真的吗?这种行为不对吗?我们希望类型的对象A执行A::f()方法而不是B::f().
是否有一些vtables在系统中的类的数量?
一个将如何vtable类,由两个或多个类继承的是什么样子?如何将C的对象表示在内存中?
与问题3相同,但具有虚拟继承.
我理解在使用多重继承时需要虚拟继承 - 它解决了Dreaded Diamond问题.
但是,如果我不使用多重继承怎么办? 是否需要虚拟继承?
我似乎记得听说它对异常很重要(抛出派生类,通过基类引用捕获).但虚拟析构函数不应该足够吗?
我已经尝试过搜索我曾经看过的参考页面,但我似乎无法找到它.
我遇到了一个可怕的钻石问题.提醒一下,这是这个问题的经典类层次结构:
B
/ \
C1 C2
\ /
D
Run Code Online (Sandbox Code Playgroud)
要解决这个问题,标准的解决方案是让C1和C2使用虚拟继承来继承B.
我的问题是B和C1来自我无法修改的SDK. 下面的示例我无法使SubClassB从Base继承.类:PureVirtualBase,Base和SubClassB来自我使用的SDK.我无法修改它们.SubClassA和Leaf是我的自定义类.我可以改变它们.
PureVirtualBase(SDK)
|
Base(SDK)
/ \
SubClassA SubClassB(SDK)
\ /
Leaf
Run Code Online (Sandbox Code Playgroud)
在这种情况下,SubClassB无法更改为使用Base的虚拟继承.怎么应该这样:
class PureVirtualBase
{
public:
PureVirtualBase()
{
cout<<"<<PureVirtualBase::PureVirtualBase" << endl;
cout<<">>PureVirtualBase::PureVirtualBase" << endl;
}
virtual int f_PureVirtualBase()=0;
};
class Base : public PureVirtualBase
{
public:
Base(std::string id) {
cout<<"<<Base::Base:"<<id << endl;
m_id=id;
cout<<">>Base::Base:"<<m_id << endl;
}
virtual int f_PureVirtualBase() { …Run Code Online (Sandbox Code Playgroud) c++ multiple-inheritance virtual-inheritance diamond-problem
我在C++中使用具有多个虚拟继承的可变参数模板来将类型聚合到单个结构定义中.
以下是一组结构示例:
struct meas { int i; };
struct meas2 : public virtual meas { int j; };
struct meas3 : public virtual meas { int k; };
Run Code Online (Sandbox Code Playgroud)
然后我使用多个虚拟继承来聚合它们:
template <typename... Args>
struct zipper : public virtual Args... {};
Run Code Online (Sandbox Code Playgroud)
然后我可以这样做:
typedef zipper<meas, meas2> meas_type;
meas* m = new meas_type;
Run Code Online (Sandbox Code Playgroud)
这些可以级联:
typedef zipper<meas3, meas_type> meas_type2;
Run Code Online (Sandbox Code Playgroud)
但是,生成的对象相当笨重:
$46 = (zipper<meas3, zipper<meas, meas2> >) {
<meas3> = {
<meas> = {
i = 0
},
members of meas3:
_vptr.meas3 = 0x400ec8,
k = …Run Code Online (Sandbox Code Playgroud) c++ multiple-inheritance virtual-inheritance variadic-templates c++11
缺少虚拟继承会对以下代码产生负面影响吗?
如果是这样,如果class A 确实包含数据成员,那么负面影响是否会与没有虚拟继承的多重继承的负面影响相同(或者更糟)?
class A
{
public :
virtual ~A ( ) { }
virtual int foo ( ) const = 0 ;
} ;
class B : public A
{
public :
virtual ~B ( ) { }
} ;
class C : public A
{
public :
virtual ~C ( ) { }
} ;
class D : public B , public C
{
public :
virtual int foo ( ) const { return 12 …Run Code Online (Sandbox Code Playgroud) c++ oop inheritance multiple-inheritance virtual-inheritance
更新:我创造了更多M,但仍然是CVE再现崩溃.摘要:删除了类中所有Bool* bools_字段的使用Base(但仍然必须定义或不发生崩溃).还删除Base::Initialize()了Rule来自Base及其后代的虚方法.附加了新的MCVE.
我已经设法为此代码创建了一个MCVE并在下面发布了它.
一些描述性细节:代码使用虚拟基类和派生类,并且实例化的某些派生类具有构造函数,这些构造函数调用从"基础"类继承的非虚方法(实际上是派生类,但在继承层次结构中高于我称之为"派生"类来初始化"基础"类数据.该方法调用在派生类中重写的虚方法.我意识到这是一件危险的事情,但是从我(可能是有限的)对C++的理解来看,它似乎应该有效,因为派生类构造函数的主体在设置"基"类虚拟表之前不会执行.在任何情况下,在调用"base"类的初始化方法期间不会发生段错误.
段错误发生在"base"类构造函数中,并且仅在构造函数的主体为空时发生.如果我向构造函数添加一个调试行,以便在到达该点时打印出来,则打印出调试行并且代码正常运行.我的猜测是,由于某种原因,编译器正在优化在"base"类的构造函数的主体执行之前应该发生的初始化,包括设置vtable.
正如主题所说,这个代码在没有使用Apple的g ++或g ++ 7.2.0进行优化编译时运行良好,并且在使用g ++ 7.2.0编译甚至-O3时运行正常.它只在编译时-O2或-O3使用Apple的LLVM实现g ++时出现段错误.该g++ --version编译器的输出是:
% /usr/bin/g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Content
Run Code Online (Sandbox Code Playgroud)
MCVE如下.
#include <iostream>
using namespace std;
class OriginalBaseClass {
public:
OriginalBaseClass(long double data1 = 1, long int data2 = 1) : data1_(data1), data2_(data2) { cout << "In OriginalBaseClass constructor\n"; }
private:
long …Run Code Online (Sandbox Code Playgroud)