Запрещает преобразования в родительский, но публично раскрывает интерфейс родителя (проблема дизайна) - PullRequest
0 голосов
/ 06 ноября 2018

Я не уверен, как реализовать (выразить в C ++) следующую проблему наиболее элегантным способом. Допустим, у нас есть библиотека, предоставляющая класс PerfectCounter с богатым не виртуальным интерфейсом. Я хочу реализовать класс DisturbedCounter, который наследуется от PerfectCounter. Новый класс должен предоставлять тот же интерфейс, что и его родительский, и, например, разрешить вызов некоторых операторов (<, >, = = и т. д.) для пар экземпляров обоих классов. Более того, я хочу запретить преобразования между двумя классами (в обоих направлениях).

DisturbedCounter может наследоваться в частном порядке от PerfectCounter. Он будет блокировать преобразования от DisturbedCounter до PerfectCounter. Тем не менее, мне придется явно объявить 99% API PerfectCounter как public в DisturbedCounter. Это означает много написания и обслуживания в будущем.

Есть ли лучший способ решить эту проблему?

Я могу использовать C ++ 17.

Ответы [ 2 ]

0 голосов
/ 06 ноября 2018

Я не уверен, что это именно то, что вам нужно, поскольку DisturbedCounter не наследуется от PerfectCounter. Он использует CRTP , чтобы избежать преобразований, и он должен позволять вам выполнять реализацию каждого метода только один раз (за исключением тех, которые действительно должны отличаться), и вам не нужно using из базового класса , Я не очень хорошо разбираюсь в шаблонах, так что, возможно, кто-то разорвет их на части, но если нет, то это может дать вам некоторое представление, и это может быть чем-то, на чем можно основываться. Много шаблонов отсутствует.

#include <iostream>

template<class T>
struct Common {
protected:
    double m_count;

public:
    Common() : m_count(0) {}
    Common& operator=(const Common& rhs) {
        m_count = rhs.m_count;
        return *this;
    }

    operator double () const { return m_count; }
    double get() const { return m_count; }
};

// type specific implementation
struct PerfectCounter : Common<PerfectCounter> {
    void count() {
        m_count += 10.0;
    }
};

// type specific implementation
struct DisturbedCounter : Common<DisturbedCounter> {
    void count() {
        m_count += 9.9;
    }
};

int main() {
    PerfectCounter a;
    a.count();
    DisturbedCounter b;
    b.count();

    //a = b; // error
    //b = a; // error

    if( a>b ) std::cout << "a>b\n";

    std::cout << a << " " << b << "\n";
}

выход

a>b
10 9.9
0 голосов
/ 06 ноября 2018

Вы можете позволить DisturbedCounter наследовать в частном порядке от PerfectCounter. Тогда преобразования между ними не будут разрешены (поскольку DisturbedCounter в этом случае не является PerfectCounter, он просто реализован в терминах one).

Затем вы можете использовать директивы using для публичного представления частей интерфейса PerfectCounters, которые вы хотите, чтобы они были публично доступны в DisturbedCounter, и добавления реализаций любых операторов сравнения, которые вы хотите.

Конечно, есть и другие способы сделать это, но это как минимум один из них, который вы должны рассмотреть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...