Уловка для включения приведения к не-publi c наследованиям - PullRequest
0 голосов
/ 05 августа 2020

Это продолжение моего предыдущего связанного вопроса . Там я исследовал проблему, что восходящее и понижающее преобразование работает правильно только для отношений наследования publi c. Например, этот код даже не компилируется:

class A {
};

class B : protected A {
};

int main() {
  B b;
  static_cast<A*>(&b);
};

G ++ выдает следующую ошибку:

t.cc: In function ‘int main()’:
t.cc:10:21: error: ‘A’ is an inaccessible base of ‘B’
   10 |   static_cast<A*>(&b);
      |                     ^

Однако я думаю, что нашел следующий трюк, чтобы преодолеть это ограничение. Мы можем выполнить приведение внутри класса, а затем экспортировать функциональность приведения как метод publi c:

#include <iostream>

class A {
};

class B : protected A {
  public:
    A* getA() {
      return static_cast<A*>(this);
    };

    static B* fromA(A* a) {
      return static_cast<B*>(a);
    };
};

int main() {
  B b;

  // Does not even compile
  //std::cout << static_cast<A*>(&b);

  // works like charm
  std::cout << b.getA() << '\n';

  // works also in the reverse direction, although it needs a static method
  std::cout << B::fromA(b.getA()) << '\n';
};

Что ж, признаю, это не очень красиво. Мои тесты (в более сложном коде) показывают, что он работает, но я еще не очень уверен.

Это правильный код C ++ и правильная практика?

1 Ответ

1 голос
/ 05 августа 2020

Концептуально getA в порядке. B выбирает выставить в нем A. Его можно упростить до return this;, приведение не требуется.

У меня есть оговорки по поводу fromA, потому что это подразумевает, что все A s - B s, что может быть неверно. Вам следует ограничить доступность fromA местами, где вы можете доказать, что все A являются B s.

Безопасное снижение может быть выполнено с помощью dynamic_cast.

ссылка на static_cast

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