繁体   English   中英

可以使用C ++聚合初始化来构造实现接口的类的实例吗?

[英]Can C++ aggregate initialization be used to construct an instance of a class which implements an interface?

我希望有人可以给我一些技术细节,说明为什么以下内容无法编译,如果可能的话,还有一个解决方法。

我有一个名为Foo的现有结构,以及使用初始化列表创建Foo实例的代码。 此代码编译和工作:

struct Foo {
    int id1;
    int id2;
};

int main()
{
    Foo f({1,2});

    return f.id1;
}

我希望Foo能够实现一个接口:

struct Interface {
    // All pure virtual methods, but this won't compile even if empty
};

struct Foo : public Interface{
    int id1;
    int id2;
};

int main()
{
    Foo f({1,2});

    return f.id1;
}

此代码不再编译,并且存在错误

cannot convert argument 1 from 'initializer list' to 'const _Ty &'

(错误会根据您的确切编译器而改变。)

我发现有关聚合初始化的标准的这一部分:

[dcl.init.aggr] / 1聚合是一个数组或类(第12条),1.1没有用户提供的,显式的或继承的构造函数(15.1),1.2没有私有或受保护的非静态数据成员(第14条) ),1.3没有虚函数(13.3),1.4没有虚拟,私有或受保护的基类(13.1)。

虽然我不确定聚合初始化是否发生在这里。 有人可以解释正在发生的错误,如果可能的话,可以提供我可以对界面进行的更改吗? 我有几个需要这个接口的现有结构,以及许多使用这种形式的初始化的现有代码,我想尽可能少地重写它。 谢谢!

您需要初始化基类,即使它是空的:

Foo f({{},1,2});

看到它生活在godbolt上

在你所指的部分的标准中,我们可以在[dcl.init.aggr] p4.2中看到这个例子:

 struct base1 { int b1, b2 = 42; }; struct base2 { base2() { b3 = 42; } int b3; }; struct derived : base1, base2 { int d; }; derived d1{{1, 2}, {}, 4}; derived d2{{}, {}, 4}; 

初始化d1.b1为1,d1.b2为2,d1.b3为42,d1.d为4,d2.b1为0,d2.b2为42,d2.b3为42,d2.d为4。 - 末端的例子]

另见[dcl.init.aggr] p2 ,它解释了聚合的元素是什么:

聚合的元素是:

- 对于数组,数组元素按增加的下标顺序,或
- 对于一个类, 声明顺序中的直接基类,后跟声明顺序中不是匿名联合成员的直接非静态数据成员([class.mem])。

[dcl.init.aggr] p3说:

当聚合由[dcl.init.list]中指定的初始化列表初始化时,初始化列表的元素将被视为聚合元素的初始化器。 ...

注意,答案假设C ++ 17或更高版本,因为在C ++ 17之前,不允许聚合具有基类

@ShafikYaghmour解释了为什么当Interface为空时,聚合初始化不能像以前那样完成。

但是,如果Interface具有虚函数,如问题所示,来自Interface的派生类将不是聚合 因此,实现Interface并将数据成员保存为Foo必须实现构造函数。 我看到的最简单的方法(根据数据成员的“平凡性”,在速度方面可能不是最有效的)是这样的:

struct Interface {
   // All pure virtual methods, but this won't compile even if empty
   virtual void bar() =0;
   };

struct Foo_data{ //change the name of the aggregate
  int id1;
  int id2;
  };

struct Foo
  :Interface  //Foo has virtual function => Foo is not an aggregate
  ,Foo_data
  {
  Foo() =default;
  Foo(Foo_data data):Foo_data(std::move(data)){}//a constructor must be provided
  void bar() override {}
  };

int main(){
  Foo f({1,2});
  return f.id1;
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM