网上满是"可怕的钻石问题"的解释.StackOverflow也是如此.我想我明白这一点,但我没有将这些知识转化为理解类似但不同的东西.
我的问题始于一个纯粹的C++问题,但答案很可能转移到MS-COM细节中.一般问题是:
class Base { /* pure virtual stuff */ };
class Der1 : Base /* Non-virtual! */ { /* pure virtual stuff */ };
class Der2 : Base /* Non-virtual! */ { /* pure virtual stuff */ };
class Join : virtual Der1, virtual Der2 { /* implementation stuff */ };
class Join2 : Join { /* more implementation stuff + overides */ };
Run Code Online (Sandbox Code Playgroud)
这不是经典的钻石解决方案.究竟"虚拟"在这里做什么?
我真正的问题是试图理解我们朋友在CodeProject上的讨论.它涉及一个自定义类,用于为Flash播放器创建透明容器.
我以为我会尝试这个地方的乐趣.事实证明,以下声明使您的应用程序崩溃,其中包含Flash播放器的第10版.
class FlashContainerWnd: virtual public …Run Code Online (Sandbox Code Playgroud) 让我们从代码片段开始:
#include <iostream>
struct God{
God(){_test = 8;}
virtual ~God(){}
int _test;
};
struct Base1 : public virtual God{
//Base1(){std::cout << "Base1::Base1" << std::endl;} //enable this line to fix problem
virtual ~Base1(){}
};
struct Base2 : public virtual Base1{
virtual ~Base2(){}
};
struct A1 : public virtual Base2{
A1(){std::cout << "A1:A1()" << std::endl;}
virtual ~A1(){};
};
struct A2 : public virtual Base2{
A2(){std::cout << "A2:A2()" << std::endl;}
virtual ~A2(){};
};
struct Derived: public virtual A1, public virtual A2{
Derived():Base1(){std::cout << …Run Code Online (Sandbox Code Playgroud) class IA
{
public:
virtual void a() = 0;
};
class A: virtual public IA
{
public:
virtual void a()
{
}
};
class IB: virtual public IA
{
public:
virtual void b() = 0;
};
class B: virtual public IB, public A
{
public:
virtual void b()
{
}
};
Run Code Online (Sandbox Code Playgroud)
你是否总是像我一样继承你的界面虚拟?如果没有,您将如何强制执行上述代码?
请考虑以下代码:
#include <iostream>
#include <typeinfo>
#include <type_traits>
using namespace std;
struct A { int data; };
struct B1 : A {};
struct B2 : virtual A {};
struct Base1 : virtual A {};
struct Base2 : virtual A {};
struct Derived : Base1, Base2 {};
int main() {
cout << sizeof(B1) << endl;
cout << sizeof(B2) << endl;
cout << sizeof(Derived) << endl;
cout << std::is_polymorphic<B1>::value << endl;
cout << std::is_polymorphic<B2>::value << endl;
cout << std::is_polymorphic<Derived>::value << endl;
return 0; …Run Code Online (Sandbox Code Playgroud) 为什么以下代码中的TemplateChild不起作用?我知道虚方法不能是模板,但为什么显式实例化模板方法不能覆盖虚方法?
#include <iostream>
class VirtBase
{
public:
VirtBase() {};
virtual ~VirtBase() {};
virtual void method( int input ) = 0;
virtual void method( float input ) = 0;
};
class RegularChild : public VirtBase
{
public:
RegularChild() {};
~RegularChild() {};
void method( int input ) {
std::cout << "R" << input << std::endl;
}
void method( float input ) {
std::cout << "R" << input << std::endl;
}
};
class TemplateBounceChild : public VirtBase
{
public:
TemplateBounceChild() {};
~TemplateBounceChild() {}; …Run Code Online (Sandbox Code Playgroud) 昨天,我遇到了这个问题:迫使不合格的名称成为依赖值最初,它似乎是一个与破坏的VC++行为有关的非常具体的问题,但在尝试解决它时,我偶然发现了虚拟继承的使用模式我没有之前遇到过(在我告诉你问题之后,我会在一秒钟内解释).我发现它很有趣,所以我在SO和google上寻找它,但我找不到任何东西.也许,我只是不知道它的正确名称("方法注入"是我的猜测之一),它实际上是众所周知的.这也是我对社区提问的一部分:这是一种常见的使用模式还是另一种已知范式的特例?您是否看到任何可以通过其他解决方案避免的问题/陷阱?
此模式可以解决的问题如下:假设您有一个Morph带有方法的类doWork().在其中doWork(),调用了几个函数,其实现应该由用户选择(这就是调用类的原因Morph).让我们称之为函数变色龙(因为Morph类最终不知道它们将是什么).实现这一目标的一种方法当然是使变色龙成为Morph类的虚方法,这样用户就可以派生出来Morph并覆盖所选择的方法.但是,如果期望用户使用不同的组合来选择不同变色龙的实现,该怎么办呢?然后,对于每个组合,必须定义新类.另外,如果有多个Morph类相同的函数应该是变色龙呢?用户如何重用已经实现的替换?
至于"必须定义多个类"的问题,立即模板跳进了一个人的脑海.用户不能通过将类作为定义所需实现的模板参数来选择他想要的变色龙实现吗?即类似的东西Morph<ReplaceAB>应该有效地取代变色龙,A()并且B()在doWork()某些实施中,留下可能的其他变色龙,例如C(),未触动过.使用C++ 11和可变参数模板,即使组合也不会成为问题:Morph<ReplaceAB, ReplaceC, WhateverMore...>嗯,确实,这种模式可以做什么(参见下面的解释):
#include <iostream>
using namespace std;
// list all chameleons, could also be make some of them
// pure virtual, so a custom implementation is *required*.
struct Chameleons
{
virtual void A() { cout << "Default A" << endl; }
virtual void B() { cout << "Default B" …Run Code Online (Sandbox Code Playgroud) 在现代C++中是否有一种方法可以防止类被虚拟继承,同时允许定期继承?现在对我来说似乎不可能,但这种语言中有太多东西似乎是不可能的.
我正在努力更好地理解vTables和vPointers为我们提供的解析内存布局.我完全理解多态性及其工作原理,并且确实没有问题,但是有一些小事情我似乎在关于内存布局和理解虚拟基本偏移方面绊倒.我知道这些东西在每天的C++代码中都不是完全必要的,但是我的兴趣是获取正在发生的事情.
我一直在指这个站点,以帮助理解由于使用虚拟继承而发生的内存布局.
在页面的虚拟继承部分大约有一半的时间内,它为生成的vTable提供了视觉效果,但是我想澄清一下我认为发生了几个事件的顺序:
http://www.phpcompiler.org/articles/virtualinheritance/vtable2.png
在上图中,在我看来:
LeftvTable的vPtrLeft类的唯一值(Left::b)int Left::b= 8,因此我们偏移Top::a8,并将其添加到布局的底部.http://www.phpcompiler.org/articles/virtualinheritance/vtable3.png
在这上面的图片,在我看来是:
Left::b)Right::c)Bottom该类的任何唯一数据,Bottom::dBottom类的内存布局对我来说,我认为上述过程在很多情况下确定内存布局是有意义的,但是我想知道如果我改变一些事情会发生什么.
Bottom虚拟地继承了两者Left和内存,内存布局将如何变化RightLeft和Right定期,但是说Right定义它自己int a,显然这会使它bottom.a等于bottom.Right::a最近覆盖的任何东西,但是这将被放置在内存布局中?我的每个问题都有一个提案布局(2),并想知道我背后的想法是否正确,如果没有,为什么......谢谢!
1.)
+--Bottom---+ …Run Code Online (Sandbox Code Playgroud) 我正在使用C++14§3.11/ 2中的示例:
struct B { long double d; };
struct D : virtual B { char c; }
Run Code Online (Sandbox Code Playgroud)
在clang,g ++和VS2015中运行下面的代码片段之后
#include <iostream>
struct B { long double d; };
struct D : /*virtual*/ B { char c; };
int main()
{
std::cout << "sizeof(long double) = " << sizeof(long double) << '\n';
std::cout << "alignof(long double) = " << alignof(long double) << '\n';
std::cout << "sizeof(B) = " << sizeof(B) << '\n';
std::cout << "alignof(B) = " << alignof(B) << …Run Code Online (Sandbox Code Playgroud) 代码如下(使用G ++编译的C++ 11代码 - 在Ubuntu 16.04上为5.4):
#include <iostream>
using namespace std;
class Base
{
public:
virtual void show()
{
cout << "Base" << endl;
}
virtual void func()
{
cout << "func in Base" << endl;
}
protected:
int base = 15;
};
class A: public virtual Base
{
public:
void show() override
{
cout << this << endl;
cout << 'A' << endl;
}
void func() override
{
cout << this << endl;
cout << "func in A" << …Run Code Online (Sandbox Code Playgroud) c++ ×10
inheritance ×3
alignment ×1
c++11 ×1
c++14 ×1
com ×1
polymorphism ×1
rtti ×1
templates ×1
virtual ×1