从派生类调用基于模板的对象

时间:2018-03-14 10:49:09

标签: c++11 templates

我正在寻找这个特定问题的解决方案。 我有一个IOWriter模板类,有几种写入不同类型值的方法。

现在在我的基类TestBase中,我创建了一个带有通用ref输入的函数模板。这会将值转发给基类的IOWriter类实例。

在派生类TestDerived中,我有一个专门的IOWriter (i.e. Writer)类成员实例writer,它应该由自己的函数模板调用以进行转发。

template <typename WriterType>
struct IOWriter
{
    template < typename T >
    QString Write(WriterType* obj, T value)
    {
        std::cout << "Not Working: TestBase" << std::endl;
        return obj->write(QString("true"));
    }
};

class TestBase
{
    template <typename T>
    friend struct IOWriter;

    //Uses default implementation
    IOWriter<TestBase> writer;

    // pure virtual function called by IOWriter
    virtual QString write(const QString& value) = 0;

public:
    template <typename T>
    QString Write(T&& value)
    {
        return writer.Write(this, std::forward<T>(value));
    }
};

class TestDerived : public TestBase
{
    template <typename T>
    friend struct IOWriter;

    // TestDerived specific implementation
    struct Writer : public IOWriter<TestDerived>
    {
        // Shadows base implementation
        QString Write(TestDerived* obj, bool value)
        {
            std::cout << "Working: TestDerived" << std::endl;
            return obj->write(QString("false"));
        }
    };

    Writer writer;

    // Called by Writer
    QString write(const QString& value) override
    {
        return "derived";
    }

public:
    template <typename T>
    QString Write(T&& value)
    {
        return writer.Write(this, std::forward<T>(value));
    }
};

现在在我的代码中我可以这样称呼它:

void working()
{
    int value = 0;
    auto uptr = new TestDerived();
    uptr->Write(value);
    delete uptr;
}

工作正常。但是,当我将创建的指针存储为TestBase时,它逻辑上调用TestBase::Write,因此永远不会调用TestDerived::writer

void notWorking()
{
    int value = 0;
    TestBase* uptr = new TestDerived();
    uptr->Write(value);
    delete uptr;
}

现在我知道这是正确的,但我正在寻找一种方法让TestBase::Write使用/调用专门的TestDerived::Writer而不是自己的。{/ p>

注意: IOWriter不能拥有虚函数,因为那里有模板成员函数

1 个答案:

答案 0 :(得分:1)

哦,程序员生活中的美好时光,当他/她意识到设计不符合需求并考虑重写大部分代码时......我喜欢它:D

好的,首先必须与问题无关,但仍然是:

  • 在多态类上使析构函数成为虚拟。
  • 使用智能指针,不要使用raw new / delete。

好的,不是手头的问题:

我看到的一个解决方案是使Bridge Pattern适应您的问题:

这意味着:

  • 制作Write虚拟<{li>的IOWriter
  • TestBasewriter指向IOWriter的多态基指针
  • 使用TestDerived::writer而非Writer
  • 构建IOWriter
  • Write
  • 中删除TestDerived方法

这是最终的代码:(我用int更改了QSString以便能够更快地测试它):

final code
template <typename WriterType> struct IOWriter
{
    virtual int Write(WriterType* obj, int value)
    {
        return obj->write(value * 10 + 3);
    }
    virtual ~IOWriter() = default;
};

struct TestBase
{
    //Uses default implementation
    std::unique_ptr<IOWriter<TestBase>> writer;

    TestBase(std::unique_ptr<IOWriter<TestBase>> writer) : writer{std::move(writer)} {}

    // pure virtual function called by IOWriter
    virtual int write(int value) = 0;

    template <typename T> int Write(T value)
    {
        return writer->Write(this, value);
    }
    virtual ~TestBase() = default;
};

struct TestDerived : public TestBase
{

    // TestDerived specific implementation
    struct Writer : public IOWriter<TestBase>
    {
        // Shadows base implementation
        int Write(TestBase* obj, int value) override
        {
            return obj->write(value * 10 + 4);
        }
    };

    TestDerived() : TestBase(std::make_unique<Writer>()) {}

    // Called by Writer
    int write(int value) override
    {
        return value;
    }
};

auto test()
{
    std::unique_ptr<TestBase> uptr = std::make_unique<TestDerived>();
    return uptr->Write(7);
}