将私有参数转发到派生类虚方法

时间:2016-01-28 16:41:00

标签: c++ inheritance virtual-functions

考虑以下两个类:

class Parent
{
private:
    char outputBuffer[100];

protected:
    virtual void WriteOutput() = 0;
};


class Child : public Parent
{
private:
    double value1;
    double value2;
    void WriteOutput()
    {
        sprintf(outputBuffer, "%.2f %.2f", value1, value2);
    }
};

父级定义一个virtual函数,然后在子级中实现,其目的是将格式化的字符串写入输出缓冲区。

我的挑战是我希望输出缓冲区不能直接对子类可见。换句话说,我希望WriteOutput看起来像:

void WriteOutput()
{
    myFcn("%.2f %.2f", value1, value2);
}

但是myFcn()看起来像什么?它应该只是转发到sprintf,但支持sprintf中的varags所需的语法让我感到困惑。是否可以传递可变数量的参数?我在示例中显示了两个值,但不同的子项将具有不同数量的值,因此我必须保留sprintf的vararg功能。请注意,性能在这里很重要,所以我不能有不必要的字符串副本。

如果在这种情况下有一个更好/更有效的sprintf替代方案,我可以考虑一下。感谢。

2 个答案:

答案 0 :(得分:3)

Sutter and Alexandrescu's C++ Coding Standards中,您可以找到以下项目:

  
      
  1. 考虑将虚拟功能设为非公共功能,将公共功能设置为非虚拟功能。 68
  2.   

我相信,即使你的问题没有特别涉及公共/私人方面,其理由也在这里。非virtual方法应该说"外部" 它的作用virtual方法应该说 它是如何做到的。

因此,他们不需要具有相同的签名。事实上,这是怎么回事:

class Parent
{
private:
    char outputBuffer[100];

protected:
    virtual void WriteOutputImp(char outputBuffer[100]) = 0;

public:
    void WriteOutput()
    {
        WriteOutputImp(outputBuffer);
   }
};


class Child : public Parent
{
private:
    double value1;
    double value2;

protected:
    virtual void WriteOutputImp(char outputBuffer[100])
    {
        sprintf(outputBuffer, "%.2f %.2f", value1, value2);
    }
};

编辑正确地提及@ 5gon12eder(恕我直言),当您正在使用它时,您可以考虑将char ...[100]更改为更安全的内容。这完全正确,但是另外一点。

答案 1 :(得分:0)

您可以使用新的可变参数模板。即。

#include <iostream>
#include <iomanip>

void write()
{  }

template<typename... Params>
void write(double toPrint, Params... args)
{
    std::string str = "%.2f";
    const int size = sizeof...(args);
    if(size > 0U)
        str += " ";
    sprintf(outputBuffer, str.c_str(), toPrint);

    write(args...);
}

您可以通过WriteOutput这样的write(5.1, 1.23, mydoublevalue, 9.993)个人方法拨打此电话。 但是,您可能希望最小化sprintf次呼叫,并采用其他方法:

template<typename... Params>
std::string construct()
{ return std::string(); }

template<typename... Params>
std::string construct(double toPrint, Params... args)
{
    std::string str = "%.2f";
    const int size = sizeof...(args);
    if(size > 0U)
        str += " ";
    str += construct(args...);

    return str;
}

template<typename... Params>
void write(Params... args)
{
    sprintf(outputBuffer, (construct(args...)).c_str(), args...);
}

通话相同,但只使用一次sprintf通话。看到它正常工作online