【问题标题】:User-defined constructor overload not being parameter-matched to the overload with the argument's superclass用户定义的构造函数重载与参数超类的重载没有参数匹配
【发布时间】:2019-08-09 22:11:52
【问题描述】:

按照下面的代码-sn-p,我尝试通过Boo<T>::Boo(Foo const &) 构造函数重载传递Boo<int> 实例,但我无法做到。

#include <iostream>

struct Foo { };

template <typename T>
struct Boo : public Foo
{
    // Boo(Boo<T> const &) = delete; // Leaves (2) without a constructor 

    Boo()            { std::cout << "Beep " << sizeof(T) << std::endl; }
    Boo(Foo const &) { std::cout << "Boop " << sizeof(T) << std::endl; }
};

void fun(Foo const &) { }

int main()
{
    Boo<int> x;       // (1) Output: Beep 4
    Boo<int> y(x);    // (2) Output:
    Boo<double> z(x); // (3) Output: Boop 8
    fun(x);           // (4) Compiles

    return 0;
}

在 code-sn-p 中,我尝试编写一个简单的场景,如果需要,可以复制粘贴来玩弄。

  1. 在 (1) 处,我们生成一个 Boo&lt;int&gt; 实例 x,它使用 Boo&lt;T&gt;::Boo() 构造函数重载。
  2. 在(2)处,我们将实例x传递给实例y的构造函数,它使用隐式定义的复制构造函数Boo&lt;T&gt;::Boo(Boo&lt;T&gt; const &amp;)。因此,我们不会收到输出消息。
  3. 在(3)处,我们将实例x传递给实例z的构造函数,它使用Boo&lt;T&gt;::Boo(Foo const &amp;)构造函数重载。
  4. 在 (4) 处,我们确认 Boo&lt;int&gt; 可以被编译器隐式转换为 Foo const &amp; 并传递给 fun(Foo const &amp;) 函数。

问题:我怎样才能让 (2) 通过与 (3) 相同的构造函数,为什么它还没有这样做?

如果有人能看到我错过的内容,我将不胜感激,如果有人指出我的话。

【问题讨论】:

  • 有什么问题?
  • 为什么要让 2 和 3 做同样的事情?隐式复制构造函数在 2 中是完全匹配的,因此它将是首选。
  • @ÖöTiib 谢谢你,这肯定会在未来。 @1201ProgramAlarm 感谢您的修复。 @NathanOliver 我同意你的看法,尽管在我的情况下,无论T 如何,我都希望所有Boo&lt;T&gt; 都通过与(3)相同的构造函数。你提到这是一个“完全匹配”,我不能否认,但这也是为什么我添加了注释代码行,deletes 是隐式定义的构造函数,以强制 (2) 表现为 (3 ),但 (2) 不能匹配任何可用的构造函数。不过,fun 函数可以证明它确实匹配。
  • 所以,你应该依赖静态多态性(这里,基于模板)而不是运行时多态性(参考你写的)。为什么不? template&lt;typename T, typename = std::enable_if&lt;std::is_assignable&lt;typename Foo&gt;, T&gt;::value&gt; Boo(T const &amp;) 然后继续你的代码
  • @user9335240 感谢您的评论。我认为您的建议是一个可能的解决方案,具体取决于所需的方法。随意将其作为替代解决方案发布在答案部分。我个人试图确定是否有一种方法可以有效地使用运行时多态性来实现这一目标。

标签: c++ inheritance constructor overloading


【解决方案1】:

使用委托构造函数:

template <typename T>
struct Boo : public Foo
{
    Boo(Boo<T> const & arg) : Boo(static_cast<Foo const&>(arg)) {};

    Boo()            { std::cout << "Beep " << sizeof(T) << std::endl; }
    Boo(Foo const &) { std::cout << "Boop " << sizeof(T) << std::endl; }
};

修复它的原因是不再有隐式复制构造函数,这比强制转换为 Foo const&amp; 和使用构造函数 Boo&lt;T&gt;::Boo(Foo const&amp;) 并手动调用它更好。

【讨论】:

  • 非常感谢您的回答。这是我在写问题时所采用的实现,但我不确定它是否是最健壮或最有效的,代码方面。您的解释使我清楚并有信心继续采用这种方法。如果您以某种方式知道或可以弄清楚为什么删除隐式复制构造函数不会强制编译器根据其多态性选择 Boo&lt;T&gt;::Boo(Foo const &amp;) 构造函数,请在下面编辑您的答案或评论。也许它根本就没有编程这样做。
  • @HelloWorld 删除的函数仍然是一个定义,所以Boo&lt;T&gt;::Boo(Boo&lt;T&gt; const&amp;) 仍然会被选中。但是既然是deleted函数,就会出现编译时错误(这就是deleted函数的点)。这个解决方案没有什么低效的地方,只要你在编译时进行一些优化。
  • 完美,你已经解决了我所有的顾虑。从我的角度来看,这个答案是完整的。谢谢你,Artyer。
猜你喜欢
  • 2012-11-30
  • 2021-09-14
  • 2019-11-29
  • 2018-05-22
  • 1970-01-01
  • 1970-01-01
  • 2012-07-22
  • 2019-07-16
  • 2013-11-17
相关资源
最近更新 更多