用可变参数继承构造函数

时间:2019-05-12 10:35:46

标签: c++ inheritance

我有一个带有两个构造函数的简单类A。其中之一具有通用参数。 B类只是派生类,我想使用A类派生的构造函数实例化B类。

一切正常,直到我想使用可变参数的特殊功能。最后一条语句会引发编译器错误,提示:

"sorry, unimplemented: passing arguments to ellipsis of inherited constructor B::B(int, ...) [inherited from A]".

如何解决该问题。

class A {
    public:
        A(float f){
            std::cout << "Do something" << std::endl;
        }

        A(int a, ...){
            std::cout << "Do something else" << std::endl;
        }
};

class B : public A {
    using A::A;
};

int main(){

    A a(2.0f); // works
    B b(1.0f); // works

    A c(1, 2, 3); // works
    B d(1); // works
    B e(1, 2); // doesn't work

    return 0;
}

输出为:

Do something
Do something
Do something else
Do something else
ERROR :(

3 个答案:

答案 0 :(得分:1)

您需要分别继承带有可变参数的函数。

[编辑]

class B : public A {
public:
    using A::A;
    B(int a, int ...) :A(a) {}
};

这样,您的构造函数在main()中进行调用就可以正常工作。

A a(2.0f); // calls A(float f)
B b(1.0f); // calls A(float f)

A c(1, 2, 3); // calls A(int a, ...)
B d(1); // calls A(int a, ...)
B e(1, 2); // calls A(int a, ...)

输出将是:

Do something
Do something
Do something else
Do something else
Do something else

答案 1 :(得分:1)

首先,我要提到Variadic arguments是一种 C 语言功能,它只是在C ++中继承的(为了兼容性而保留)。

现代C ++提供了类型保存替代方案,例如Parameter packInitializer Lists,应首选IMHO。

不过,那是一个可行的解决方案。

当我尝试模仿类似printf()之类的东西时,我曾经发现它。那时,我注意到vprintf()的存在,并了解了它的优点和优点。

这是基本思想,我试图解决OP的困境:

#include <cstdarg>
#include <iostream>

class A {
  public:
    A(float f)
    {
      std::cout << "A::A(" << f << ")\n";
    }

    A(int n, ...)
    {
      std::cout << "A::A(";
      va_list args;
      va_start(args, n);
      getArgs(n, args);
      va_end(args);
      std::cout << ")\n";
    }
  protected:
    A()
    {
      std::cout << "A::A()\n";
    }

    void getArgs(int n, va_list args)
    {
      std::cout << n;
      for (int i = 0; i < n; ++i) {
        float arg = va_arg(args, double); // Please, note, float is not a standard argument type.
        std::cout << ", " << arg;
      }
    }
};

class B: public A {
  public:
    B(float f): A(f)
    {
      std::cout << "in B::B(float)\n";
    }

    B(int n, ...)
    {
      std::cout << "in B::B(";
      va_list args;
      va_start(args, n);
      getArgs(n, args);
      va_end(args);
      std::cout << ")\n";
    }
};

#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  std::cout << "Test flavors of A::A():\n";
  DEBUG(A a1(1.23f));
  DEBUG(A a2(3, 1.2f, 2.3f, 3.4f));
  std::cout << "Test flavors of B::B():\n";
  DEBUG(B b1(1.23f));
  DEBUG(B b2(3, 1.2f, 2.3f, 3.4f));
}

输出:

Test flavors of A::A():
A a1(1.23f);
A::A(1.23)
A a2(3, 1.2f, 2.3f, 3.4f);
A::A(3, 1.2, 2.3, 3.4)
Test flavors of B::B():
B b1(1.23f);
A::A(1.23)
in B::B(float)
B b2(3, 1.2f, 2.3f, 3.4f);
A::A()
in B::B(3, 1.2, 2.3, 3.4)

Live Demo on coliru

提示:

带有可变参数的IMHO常见陷阱是默认参数提升,例如,此处:Variadic arguments – Default conversions。 (我在示例代码中与之相关的地方添加了注释。)

答案 2 :(得分:1)

@Ekin:您的想法很棒。以下代码满足了我的所有愿望(我只需要为Veradic构造函数:D做一个特殊情况即可。)

class B : public A {
public:
    using A::A; // Takes care of all normal constructors

    B(int a, int ...) :A(a) {}  // Takes care of the veradic constructor
};