эмуляция c ++ ключевого слова super - PullRequest
0 голосов
/ 17 октября 2019

До тех пор, пока 'super' не будет реализован в c ++, я ищу способ эмулировать его сам. Мотивация: Вот типичный сценарий:

class A
{
    void SomeMethod();
}

class B : public A
{
    void SomeMethod() override;
}

void B::DoSomething()
{
    A::SomeMethod();
}

Все хорошо, пока кто-то не вставит класс между:

class C : public A
{
    void SomeMethod() override;
}

и не изменит наследование:

class B : public C {...}

В большинстве случаев я бы хотел, чтобы вызывался непосредственный базовый класс, что произойдет только в том случае, если я явно заменю все вызовы A :: на вызовы C ::.

Ключевое слово 'super' будетЗдесь лучше использовать, где это означает: «использовать непосредственную базу, но выдать ошибку компилятора, если она неоднозначна».

Читая некоторые предложения, я попытался определить следующее:

class A
{
    void SomeMethod();

    protected:
        using super = A;
}

class C
{
    void SomeMethod();

    protected:
        using super = C;
}

void B::DoSomething()
{
    super::SomeMethod();
}

ОднакоA :: SomeMethod () был вызван вместо C :: SomeMethod () ...

Как компилятор обрабатывает несколько псевдонимов с одинаковыми именами?

Как это исправить?

РЕДАКТИРОВАТЬ : предложенный другой вопрос - старый, где решения могут быть улучшены с использованием современного c ++.

Ответы [ 2 ]

3 голосов
/ 17 октября 2019

Один из способов решить эту проблему, но он ограничивает возможности использования класса, - сделать его шаблоном. При этом вы можете сделать базовые классы типом шаблона, и теперь у вас есть общие имена, к которым вы можете обращаться к ним. Это выглядело бы как

struct A
{
    void do_something() { std::cout << "A::do_something\n"; }
};

template <typename Super>
struct B : Super
{
    void do_something() 
    { 
        std::cout << "B::do_something\n"; 
        Super::do_something(); 
    }
};

template <typename Super>
struct C : Super
{
    void do_something() 
    { 
        std::cout << "C::do_something\n"; 
        Super::do_something(); 
    }
};

int main() 
{
    B<A> b;
    b.do_something();
    C<B<A>> c;
    c.do_something();
}

, который выводит

B::do_something
A::do_something
C::do_something
B::do_something
A::do_something

Вы можете даже использовать множественное наследование и обращаться к каждой базе индивидуально, как

template <typename Super1, typename Super2>
struct B : Super1, Super2
{
    void do_something() 
    { 
        std::cout << "B::do_something\n"; 
        Super1::do_something(); 
        Super2::do_something(); 
    }
};
0 голосов
/ 17 октября 2019

Требование не имеет смысла: какой базовый класс следует считать суперклассом?

Если ваш класс имеет единственное наследование, то вы можете облегчить бремя обслуживания, добавивusing объявление:

class B : public A
{
    using Base = A;
    //...
}

Тогда у вас есть только одна строка, которую нужно изменить.

...