草庐IT

c++ - 多重继承引起的C++拷贝构造函数调用不明确

coder 2024-02-04 原文

我在执行某项任务时遇到了问题,这是一个练习,而不是一个真正的程序。任务是定义结构 D 的复制构造函数,其行为方式与编译器生成的复制构造函数完全相同。

class Ob{
};

struct A {
Ob a;
};

struct B : A {
Ob b;
};

struct C : A, B {
Ob c;
};

struct D : C, A {
Ob d;
};

如您所见,结构 A 在结构 D 中间接派生了几次,这导致了复制构造函数定义中的歧义,如下所示:

D(const D& _d) : C(_d), A(_d), d(_d.d) {}

我的问题是如何正确定义复制构造函数?没有上述定义的代码编译通过,所以看起来应该是可以的。

MinGW 4.8.1 错误信息:

zad3.cpp:12:8: warning: direct base 'A' inaccessible in 'C' due to ambiguity     [enabled by default]
 struct C : A, B {
        ^
zad3.cpp:16:8: warning: direct base 'A' inaccessible in 'D' due to ambiguity     [enabled by default]
 struct D : C, A {
    ^
zad3.cpp: In copy constructor 'D::D(const D&)':
zad3.cpp:17:38: error: 'A' is an ambiguous base of 'D'
 D(const D& _d) : C(_d), A(_d), d(_d.d) {}
                                      ^

重要提示:这是不是重复问题“Inaccessible direct base caused by multiple inheritance”,这是关于具有不同访问说明符的公共(public)基类,最终是由转换问题引起的。这里是关于消除以相同的可见性多次继承的公共(public)基类的必需初始化器的歧义。

最佳答案

注意:答案经过根本性编辑!

问题分析:

您正在使用 multiple inheritance with a diamond problem .

更具体地说,您的结构 D 继承相同的基类 A 三次:一次直接(struct D: C,A)和两次间接(通过 C 的继承)。由于基类不是虚拟的,因此 D 有 3 个不同的 A 子对象。C++11 标准部分 10.1/4-5 称其为格子:

通常,您随后会通过显式限定来消除每个 A 的成员的歧义,告诉编译器您指的是 3 个 A 子对象中的哪一个。 C++11 第 10.1/5 节对此进行了解释。成员的语法应该是 A::a, C::aB::aD<>,如果您在外面,每个最终都以 D:: 开头。

不幸的是,C++11 section 10.2/5-6 中的成员名称查找逻辑确保直接 A 基总是使其他间接 A 基础不明确,尽管有明确的限定(甚至 using 语句)。

最终解决方案:

由于问题是由直接基类引起的,而且事实上没有办法区分这个与其他类的歧义,唯一真正有效的解决方案是使用一个空的中间类来强制使用不同的名称:

struct Ob{ int v; };    // v aded here to allow verification of copy of all members
struct A { Ob a; };
struct B : A {  Ob b; };
struct A1 : A {};       // intermediary class just for diambiguation of A in C
struct C : A1, B { Ob c; };  // use A1 instead of A
struct A2 : A { };      // intermediary class just for diambiguation of A in D
struct D : C, A2 {        // use A2 instead of A
    Ob d;
    D() { }
    D(const D& _d) : C(_d), A2(_d), d(_d.d) { }
};

int main(int ac, char**av)
{
    cout << "Multiple inheritance\n";
    D x;
    x.A2::a.v = 1;  // without A2:: it's ambiguous
    x.A1::a.v = 2;  // without A1:: it's ambiguous
    x.B::a.v = 3;
    x.b.v = 4;
    x.d.v = 5;

    D y = x;
    cout << "The moment of truth: if not 1 2 3 4 5, there's a problem!\n";
    cout << y.A2::a.v << endl;
    cout << y.A1::a.v << endl;
    cout << y.B::a.v << endl;
    cout << y.b.v << endl;
    cout << y.d.v << endl;
}

此代码编译并使用 MSVC2013、clang 3.4.1 和 gcc 4.9。


其他(非)解决方案:

我之前的回答仅基于明确的限定条件。尽管有很多批评,但我真的在 MSVC2013 上编译和测试成功了!然而,它们是一件奇怪的事情:在编辑器中,intelisence 突出了一个歧义,但编译运行良好,没有任何错误。我最初认为这是一个智能错误,但现在意识到这是一个编译器不合规性(错误?)

提示D(const D& other) : C(other), A((const B)other), d(other.d)的答案编译通过,但没有通过测试。为什么 ?因为 A((const B)other) 会将 other 理解为 B。因此 D 中的 A 将使用间接继承自 BA 的值进行初始化(所以另一个A)。这是一个极其严重的错误,我花了一段时间才注意到。

当然你可以使用虚基类。那么D中就只有一个A子对象了,解决了很多问题。但是我不知道你在设计什么,有些设计需要一个格子而不是一个虚拟的菱形。

如果你能负担得起两步复制(第 1 步:基的默认初始化;第 2 步:复制基上的目标值),当然有一些方法使用无歧义的成员函数返回正确基的引用。但这可能比上面介绍的简单解决方案更棘手且更容易出错。

关于c++ - 多重继承引起的C++拷贝构造函数调用不明确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26832200/

有关c++ - 多重继承引起的C++拷贝构造函数调用不明确的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  3. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  4. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  5. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  6. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  7. ruby-on-rails - Rails 单表继承 : How to override the value written to the type field - 2

    在我的系统中,我已经定义了STI。Dog继承自Animal,在animals表中有一个type列,其值为"Dog"。现在我想让SpecialDog继承自dog,只是为了在某些特殊情况下稍微修改一下行为。数据还是一样。我需要通过SpecialDog运行的所有查询,以返回数据库中类型为Dog的值。我的问题是因为我有一个type列,rails将WHERE"animals"."type"IN('SpecialDog')附加到我的查询中,所以我不能获取原始的Dog条目。所以我想要的是以某种方式覆盖rails在通过SpecialDog访问数据库时使用的值,使其表现得像Dog。有没有办法覆盖用于类型

  8. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  9. ruby-on-rails - 将字符串转换为 ruby​​-on-rails 中的函数 - 2

    我需要一个通过输入字符串进行计算的方法,像这样function="(a/b)*100"a=25b=50function.something>>50有什么方法吗? 最佳答案 您可以使用instance_eval:function="(a/b)*100"a=25.0b=50instance_evalfunction#=>50.0请注意,使用eval本质上是不安全的,尤其是当您使用外部输入时,因为它可能包含注入(inject)的恶意代码。另请注意,a设置为25.0而不是25,因为如果它是整数a/b将导致0(整数)。

  10. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

随机推荐