1

由于 C++ 语言限制(不支持模板化的虚函数),我的实际想法不是编译。也许你们中的一些人对以下代码片段有一些设计建议。

我想在不同类型的输入上运行不同的算法。例如,我有一个积分图像和一个灰度图像作为输入。积分图像需要 32 位像素,而我的灰度图像需要 8 位(仅作为示例)。因此,我有两个渠道:CChannel<uint8>CChannel<uint32>

因为我可以为单个图像有多个通道,所以我将通道存储在一个向量中,std::vector<CChannelBase*>......这就是 class 的理由CChannelBase

class CChannelBase
{
public:
    virtual ~CChannelBase( void ) = 0;
};

template <class ValueType>
class CChannel : public CChannelBase
{
public:
    typedef ValueType value_type_t;
    Channel(): m_data_p(0) {}
    void setData(ValueType* f_data_p) { m_data_p = f_data_p; }
    const ValueType getData( void ) { return m_data_p; }
private:
    ValueType* m_data_p;
};

我所有的算法都实现了一个接口,并且必须与每个图像通道兼容。

class IAlgorithmInterface
{
public:
    virtual ~IAlgorithmInterface() = 0;
    template <class ValueType>
    virtual void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r);
};

class CAlgorithmA : IAlgorithmInterface
{
    CAlgorithmA() {...};
    ~CAlgorithmA() {...};
    template <class ValueType>
    void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {...};
};

class CAlgorithmB : IAlgorithmInterface
{
    CAlgorithmB() {...};
    ~CAlgorithmB() {...};
    template <class ValueType>
    void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {...};
};

当然,这段代码不会编译,因为我们有虚拟模板函数。无论如何,我正在寻找一个很好的设计来克服这个问题。一个解决方案是所有类(IAlgorithmInterface, CAlgorithmA, CAlgorithmB)都被模板化,这是我不想做的事情。我在这里看到了一些帖子,其中推荐了访问者模式。但老实说,我不知道如何在我的情况下使用它。

4

2 回答 2

0

Not sure if this solves all of your problems, since there isn't much to go on as to what you actually want this code to actually "do", but with a little bit of shuffling, it compiles:

typedef float float32_t;

class CChannelBase
{
public:
    virtual ~CChannelBase( void ) = 0;
};

template <class ValueType>
class CChannel : public CChannelBase
{
public:
    typedef ValueType value_type_t;
    CChannel(): m_data_p(0) {}
    void setData(ValueType* f_data_p) { m_data_p = f_data_p; }
    const ValueType getData( void ) { return m_data_p; }
private:
    ValueType* m_data_p;
};

template <class ValueType>
class IAlgorithmInterface
{
public:
    virtual ~IAlgorithmInterface() = 0;
    virtual void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r);
};

template <class ValueType>
class CAlgorithmA : IAlgorithmInterface<ValueType>
{
    CAlgorithmA() {};
    ~CAlgorithmA() {};
    void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {};
};

template <class ValueType>
class CAlgorithmB : IAlgorithmInterface<ValueType>
{
    CAlgorithmB() {};
    ~CAlgorithmB() {};
    void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {};
};


int main()
{
}

In essence, just move the templace<class ValueType> out a level, to the class, and add it to theIAloorithmInferface` inheritance.

I fully expect to be told that this won't work for what you are trying to do, but there is no example of what you actually want these classes to do, so I can't really tell if it works or not.

于 2013-08-27T22:17:43.203 回答
0

Okay, this is kind of convoluted, but you have kind of a convoluted requirement. IAlgorithmInterface can have a template method, but it can't be virtual. You can create an intermediate class that itself is a template virtually derived from IAlgorithmInterface which proxies the template method to some code that does the real work. The real work is provided in a template parameter fed to templated derivation of IAlgorithmInterface.

This scheme allows the template method of IAlgorithmInterface to dispatch to the appropriate derived class via a downcast.

class IAlgorithmInterface
{
public:
    virtual ~IAlgorithmInterface() {}

    template <class ValueType>
    void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r);    
};

template <class ValueType, typename RealWork>
class IAlgorithmTemplate : virtual public IAlgorithmInterface
{
public:
    void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {
        RealWork()(f_channel_p, f_result_r);
    }
};

template <class ValueType>
void IAlgorithmInterface::doWork(const CChannel<ValueType>* f_channel_p,
                                 float32_t& f_result_r)
{
    IAlgorithmTemplate<ValueType> *alg
        = dynamic_cast<IAlgorithmTemplate<ValueType>*>(this);
    alg->doWork(f_channel_p, f_result_r);
}

Now, via multiple inheritance, we can create the actual interface that algorithm implementations would use. Because IAlgorithmTemplate uses virtual inheritance, there is only one IAlgorithmInterface instance. So to support ValueTypeNew, you would add a IAlgorithmTempalte<ValueTypeNew> to the inheritance list.

template <template <class> class RealWork>
class IAlgorithmBase :
    public IAlgorithmTemplate<ValueTypeOne, RealWork<ValueTypeOne> >,
    public IAlgorithmTemplate<ValueTypeTwo, RealWork<ValueTypeTwo> >,
    //...
    public IAlgorithmTemplate<ValueTypeLast, RealWork<ValueTypeLast> > {
};

Finally, each algorithm derives from IAlgorithmBase, and implements the RealWork as a template.

template <class ValueType>
struct RealAlgorithmA {
    void operator () (const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {
        //...
    }
};

class CAlgorithmA : public IAlgorithmBase<RealAlgorithmA>
{
public:
    CAlgorithmA() {...}
    ~CAlgorithmA() {...}
};
于 2013-08-27T22:18:59.080 回答