考虑以下菱形层次结构:
struct A
{
virtual void f(){}
void g(){}
};
struct B : virtual A
{
virtual void f() override{}
void g(){}
};
struct C : virtual A
{
};
struct D: B, C
{
};
int main()
{
D d;
d.f(); //B::f is called
d.g(); //B::g is called
}
Run Code Online (Sandbox Code Playgroud)
就非虚拟功能g而言,一切都很清楚:名称B::g隐藏A::g,即使名称A::g可以在不被隐藏的情况下到达C.没有含糊之处.B::g叫做.该标准在10.2 p.10中明确证实了这一点:
[注意:当使用虚拟基类时,可以沿着不通过隐藏声明的子对象点阵的路径到达隐藏声明.这不是含糊不清的.与非虚拟基类相同的用法是模棱两可的; 在这种情况下,没有唯一的名称实例隐藏所有其他名称. - 尾注] [示例:
此外,对相关问题的这个答案提供了对该问题的详尽解释.
我不明白的是上面提到的引用如何与虚函数有关f.没有名字隐藏 …
c++ virtual-functions virtual-inheritance language-lawyer c++11
考虑以下代码:
#include<iostream>
using namespace std;
class A
{
public:
A() {cout << "1";}
A(const A &obj) {cout << "2";}
};
class B: virtual A
{
public:
B() {cout << "3";}
B(const B & obj) {cout<< "4";}
};
class C: virtual A
{
public:
C() {cout << "5";}
C(const C & obj) {cout << "6";}
};
class D:B,C
{
public:
D() {cout << "7";}
D(const D & obj) {cout << "8";}
};
int main()
{
D d1;
cout << "\n";
D …Run Code Online (Sandbox Code Playgroud) c++ copy-constructor virtual-inheritance private-inheritance ctor-initializer
我不确定这是否是 Visual-C++ 编译器中的错误或未定义的行为。
struct DummyBase { virtual ~DummyBase() = default; };
struct DummyDerived : virtual public DummyBase {};
Run Code Online (Sandbox Code Playgroud)
只是一个类和一个使用虚拟继承的派生类
DummyDerived derived;
DummyBase* base = &derived;
std::cout << "Derived : " << &derived << std::endl;
std::cout << "Base : " << base << std::endl;
Run Code Online (Sandbox Code Playgroud)
当投射DummyDerived*到 DummyBase*指针时发生偏移。这似乎是由虚拟继承引起的:
Derived : 00000000002CF838
Base : 00000000002CF840
Run Code Online (Sandbox Code Playgroud)
即使指针值不同,比较也会返回 true:
std::cout << "IsSame : " << (base == &derived) << std::endl << std::endl;
Run Code Online (Sandbox Code Playgroud)
输出:
IsSame : 1
Run Code Online (Sandbox Code Playgroud)
到目前为止,一切都很好。
问题出现在以下设置中:
struct IBaseReturner
{ …Run Code Online (Sandbox Code Playgroud) c++ virtual-inheritance visual-c++ visual-studio-2013 covariant-return-types
我的代码中有以下情况,即派生类具有对基类的虚拟继承:
class Base {
int x;
public:
Base(int x): x{x} {}
virtual void f() = 0;
};
class Derived : public virtual Base {
public:
Derived() = default;
};
class Concrete: public Derived {
public:
Concrete(): Base{42} {}
void f() override {}
};
Run Code Online (Sandbox Code Playgroud)
链接:https : //godbolt.org/z/bn1EY6
GCC (trunk) 给出以下错误:error: use of deleted function 'Derived::Derived()'while Clang (trunk) 编译它没有问题。
如果我将构造函数更改为Derived() {}而不是Derived() = default在基类上定义一个空的构造函数,则GCC 可以工作。
为什么= default在这种情况下删除 GCC 中的功能?
我试图重构一些代码,同时保留现有的功能.我无法将指向对象的指针转换为基接口,然后在以后获取派生类.在某些情况下,程序使用工厂对象来创建这些对象的实例.
以下是我正在使用的类的一些示例.
// This is the one I'm working with now that is causing all the trouble.
// Some, but not all methods in NewAbstract and OldAbstract overlap, so I
// used virtual inheritance.
class MyObject : virtual public NewAbstract, virtual public OldAbstract { ... }
// This is what it looked like before
class MyObject : public OldAbstract { ... }
// This is an example of most other classes that use the base interface
class NormalObject : public …Run Code Online (Sandbox Code Playgroud) 我在过去5年的工作中假设虚拟继承打破了静态组合.
但是现在我发现,静态组合仍然保持不变,只有关于正确实例位置的附加信息.这是正确的吗?
我有一个钻石问题,看起来像这样:
__ A
/ |\
| B | \
v|/v v\|v \v
B2 B3 C
\v /v /
B4 /
\ /
D
Run Code Online (Sandbox Code Playgroud)
我尝试了很多方法来制作最好的虚拟继承,以获得没有重复,但我找不到解决方案.A类包含一个位置.这是一个示例输出:
Call: A() position pointer is: 0x2203be8
Call: B()
Call: B2() position pointer is: 0x2203be8
Call: B3() position pointer is: 0x2203be8
Call: C() position pointer is: 0x2203a28
Call: B4() position pointer is: 0x2203be8
Call: D() position pointer is: 0x2203a28
Run Code Online (Sandbox Code Playgroud)
为什么D和C没有相同的位置指针?为什么这个A ::位置没有构造函数?我应该用什么虚拟继承来解决这个问题?谢谢.
编辑:
这是一个代码示例:
class A;
class B;
class B2 : public virtual B, public virtual A;
class …Run Code Online (Sandbox Code Playgroud) 当没有涉及虚函数时,有没有办法从虚拟基类转发到派生类?这里有一些代码来演示我在说什么:
struct Base1
{
int data;
};
struct Base2
{
char odd_size[9];
};
struct ViBase
{
double value;
};
struct MostDerived : Base1, Base2, virtual ViBase
{
bool ok;
};
void foo(ViBase &v)
{
MostDerived &md = somehow_cast<MostDerived&>(v); //but HOW?
md.ok = true;
}
int main()
{
MostDerived md;
foo(md);
}
Run Code Online (Sandbox Code Playgroud)
请注意,该代码仅用于演示.我的真实场景相当复杂,涉及模板参数和从一个到另一个的转换,只知道第一个是第二个的基础; 它可以是普通或虚拟的基础,它可能有也可能没有虚函数.(参见底部的简化示例).我可以使用类型特征检测多态情况和虚拟/非虚拟基本情况,并解决除非多态虚拟基础之外的所有情况.这就是我要问的问题.
我真的想不出一种做演员的方法:
隐含的转换是正确的; 这些只做了预告.
static_cast 明确禁止从虚拟基类进行转换:
5.2.9/2 ...并且
B既不是虚拟基类,D也不是虚基类的基类D....
dynamic_cast 也不能这样做,因为downcast需要一个多态类
5.2.7/6否则,
v应该是指向多态类型的指针或glvalue(10.3).10.3/1 ...声明或继承虚函数的类称为多态类.
reinterpret_cast 在这里根本不适用.
如果 …
虚拟基类在最派生的类中初始化,所以我的猜测是继承基类的构造函数也应该工作:
struct base {
base(int) {}
};
struct derived: virtual base {
using base::base;
};
derived d(0);
Run Code Online (Sandbox Code Playgroud)
但是,这无法使用GCC 5.2.0进行编译,GCC 5.2.0尝试查找base::base(),但与Clang 3.6.2一起正常工作.这是GCC中的错误吗?
在下面的代码中,我试图创建一个Leaf对象obj来查看多层继承中的构造函数顺序,但我发现obj在这种情况下构造函数调用的结构有点奇怪.
#include<iostream>
using namespace std;
class Base1 {
public:
Base1(void) {
cout << "class Base1" << endl;
}
};
class Base2 {
public:
Base2(void) {
cout << "class Base2" << endl; }
};
class Level1 : public Base2, virtual public Base1
{
public:
Level1(void)
{
cout << "class Level1" << endl;
}
};
class Level2 : public Base2, virtual public Base1
{
public:
Level2(void)
{
cout << "class Level2" << endl;
}
};
class …Run Code Online (Sandbox Code Playgroud)