带有抽象继承的后缀运算符++

时间:2015-10-20 15:28:21

标签: c++ inheritance operator-overloading abstract

我想在结构层次结构(抽象基础A和子基础B)中实现前缀和后缀运算符++。当只在基类中实现前缀时,这很好。但是,在子类中实现后缀版本时(因为它不能在抽象类中实现),它不起作用。

struct A {
    virtual A& operator++(){std::cout << "A: prefix ++" << std::endl; return *this;}
    virtual void foo() = 0;
};

struct B : A {
    void foo() override {};
    //virtual B& operator++() override {std::cout << "B: prefix ++" << std::endl; return *this;}
    //B operator++(int i) {std::cout << "B: postfix ++" << std::endl; return *this;}
};

int main(int argc, const char * argv[]) {
    B b;
    ++b; // Compile error here if I implement postfix in B
    return 0;
}

问题是我想避免重复代码,因为所有派生类都会以相同的方式使用operator ++,所以最好不要在各自的类中实现它们。使用抽象类的重点是避免这种情况!

我的问题是:解决这个问题最优雅的方法是什么?

EDIT。错误消息:无法增加“B”类型的值

2 个答案:

答案 0 :(得分:6)

问题是派生类中的operator++将名称隐藏在基类中。尝试将以下内容添加到B

using A::operator++;

尽管如此,您可能会发现难以使后增量函数具有多态性。协变返回类型不起作用。

Live demo.

答案 1 :(得分:1)

由于您要求更优雅的方式来实现这一点,我的观点是最优雅的方法是尽可能地隐藏类的消费者的多态接口的细节。

包含多态概念的另一个类可以解决问题,并允许您轻松安全地实现后增量:

#include <memory>
#include <iostream>

// this is our non-polymorphic handle class. In this case each handle
// owns a discrete object. We could change this to shared-handle semantics by using shared_ptr if desired.
struct poly_thing
{
    // this is the polymorphic concept (interface)
    struct concept {
        virtual void increment() = 0;
        virtual std::unique_ptr<concept> clone() const = 0;
        virtual ~concept() = default;
    };

    poly_thing(std::unique_ptr<concept> p_concept)
    : _impl(std::move(p_concept))
    {}

    // must override copy constructor because of unique_ptr
    poly_thing(const poly_thing& r)
    : _impl(r._impl->clone())
    {}

    poly_thing(poly_thing&& r) = default;

    // must override copy constructor because of unique_ptr
    poly_thing& operator=(const poly_thing& r)
    {
        _impl = r._impl->clone();
        return *this;
    }

    poly_thing& operator=(poly_thing&& r) = default;

    //
    // here is our sane non-polymorphic interface.
    //        
    poly_thing operator++(int) {
        std::cout << "operator++(int)" << std::endl;
        auto clone_p = _impl->clone();
        _impl->increment();
        return poly_thing { std::move(clone_p) };
    }

    poly_thing& operator++() {
        std::cout << "operator++()" << std::endl;
        _impl->increment();
        return *this;
    }

    std::unique_ptr<concept> _impl;
};

// an implementation (model) of the concept
struct implementation_a : poly_thing::concept {
    std::unique_ptr<poly_thing::concept> clone() const override
    {
        std::cout << "cloning an a" << std::endl;
        return std::make_unique<implementation_a>(*this);
    }

    void increment() override {
        std::cout << "incrementing an a" << std::endl;
        // implementation here
    }
};

// a model derived from a model    
struct implementation_b : implementation_a {
    std::unique_ptr<poly_thing::concept> clone() const override
    {
        std::cout << "cloning a b" << std::endl;
        return std::make_unique<implementation_b>(*this);
    }

    // you can now choose whether to implement this
    void increment() override {
        // implementation here
        std::cout << "incrementing a b" << std::endl;
    }
};

// a small test
auto main() -> int
{
    poly_thing a(std::make_unique<implementation_a>());
    auto aa1 = a++;
    auto aa2 = ++a;

    poly_thing b(std::make_unique<implementation_b>());
    auto bb1 = b++;
    auto bb2 = ++b;

    return 0;
}

预期产出:

operator++(int)
cloning an a
incrementing an a
operator++()
incrementing an a
cloning an a
operator++(int)
cloning a b
incrementing a b
operator++()
incrementing a b
cloning a b