禁止虚拟模板功能的解决方法?

时间:2012-02-22 16:49:47

标签: c++ templates inheritance

我第一次尝试使用C ++构建音频合成库(EZPlug)。

该库旨在简化设置互连音频发生器和处理器对象的图形。我们可以调用EZPlugGenerators

所有处理器单元都可以接受一个或多个EZPlugGenerator作为输入。

对我来说,这些EZPlugGenerator上的所有配置方法都是可链接的,这一点非常重要。换句话说,用于设置合成图的方法应始终返回指向父对象的指针。这允许我使用一种非常好地显示对象关系的嵌套特性的语法,如下所示:

            mixer.addGenerator(
            a(new Panner())
            ->setVolume(0.1)
            ->setSource(
                a(new TriggererPeriodic())
                ->setFrequency(
                    v(new FixedValue(1), "envTriggerFreq")
                )
                ->setTriggerable(
                    a(new Enveloper())
                    ->setAllTimes(v(0.0001), v(0.05), v(0.0f, "envSustain"), v(0.01))
                    ->setAudioSource(
                        a(new SineWaveMod())
                        ->setFrequency(
                            a(new Adder())
                            ->addGenerator(a(new Adder()))
                            ->addGenerator(v(5000, "sineFreq"))
                            ->addGenerator(
                                a(new Multiplier())
                                ->addVal(v("sineFreq"))
                                ->addVal(
                                    a(new TriggererPeriodic())
                                    ->setFrequency(v("envTriggerFreq"))
                                    ->setTriggerable(
                                        a(new Enveloper())
                                        ->setAllTimes(0.1, 0.1, 0, 0.0001)
                                        ->setAudioSource(v(1, "envAmount"))
                                    )
                                )
                            )
                        )
                    )
                )

            )
        );

上述代码存储中的“a”和“v”函数并返回对象的引用,并处理检索它们并销毁它们。

我怀疑我的C ++方法看起来有点奇怪,但我发现该语言实际上可以适应我想要编程的方式。

现在回答我的问题

我想为所有可以接受继承输入的EZPlugGenerator创建一个公共超类。这个超类将有一个方法“addInput”,它将被每个子类覆盖。问题来自于我希望“addInput”返回指向子类实例的指针,而不是超类。

这是不可接受的:

EZPlugProcessor* addInput(EZPlugGenerator* generator)

因为它返回一个指向超类实例的指针,而不是破坏我很满意的可链接性的子类。

我试过了:

template<typename T> virtual T* addInput(EZPlugGenerator* obj){

但是编译器告诉我我无法创建虚拟模板函数。

我不必在这里使用继承。我可以在每个可以接受输入的EZPlugGenerator上实现'addInput'。看起来好像在单个父类下收集它们将有助于明确它们都有一些共同点,并且有助于强制addInput是将一个对象插入另一个对象的正确方法这一事实。

那么,有没有办法可以使用继承来指示一组类的每个成员都必须实现'addInput'方法,同时允许该方法返回指向子类实例的指针?

2 个答案:

答案 0 :(得分:4)

C ++中的虚函数可以具有协变返回类型,这意味着您可以定义

virtual EZPlugProcessor *addInput(EZPlugGenerator* generator) = 0;

在基类中,然后

struct MyProcessor : EZPlugProcessor {
    virtual MyProcessor *addinput(EZPlugGenerator* generator) { 
        ...
        return this;
    }
};

只要调用者知道(按他们使用的类型)该对象是MyProcessor,他们就可以将addInputMyProcessor特有的其他函数链接起来。< / p>

如果您的继承层次结构有更多级别,那么很遗憾您有时会发现自己写作:

struct MySpecificProcessor : MyProcessor {
    virtual MySpecificProcessor *addinput(EZPlugGenerator* generator) {
        return static_cast<MySpecificProcessor*>(MyProcessor::addInput(generator));
    }
};

因为无法在EZPlugProcessor中指定addInput的返回类型是“指向对象的最派生类型的指针”。每个派生类都必须“激活”自身的协方差。

答案 1 :(得分:1)

是的,C ++已经提供了协变返回类型。

class Base
{
public:
    virtual Base* add() = 0 { return <some base ptr>; }
};

class Child : public Base
{
public:
    virtual Child* add() { return <some child ptr>; }
};

另一方面,没有人能够读取您的代码,因此您可能需要考虑是否有其他方法来设置配置,而不是在C ++中编写LISP链。