использование reinterpret_cast для аргументов функции-члена

вот код:

class containerA
{};

class containerB
: public containerA
{
    public: 
        containerB () {};

        containerB(const containerB& cb)
        {
            cout << "containerB copy ctor" << endl;
        }
};

class containerC
: public containerA
{
    public:
        containerC () {};

        containerC(const containerC& cc)
        {
            cout << "containerC copy ctor" << endl;
        }
};

class myType 
{
    public:

        void someFunction(const containerB& cB) 
        {
            cout << "someFunction(containerB)" << endl;
        }
};

Если вы предполагаете, что приведенное выше определение не может быть изменено, с помощью каких механизмов можно было бы вызвать метод «someFunction» myType с аргументом типа «const containerC&»?

Все, что я смог найти, это публично вывести новый тип из myType и переопределить «someFunction» с помощью reinterpret_cast следующим образом:

class myTypeNew
: public myType
{
    public:
        void someFunction(const containerC& cC)
        {
            cout << "someFunction(containerC)" << endl;

            const containerB& cbRef = reinterpret_cast<const containerB&>(cC);

            myType::someFunction(cbRef);
        }
};

Это безопасно? Я предполагаю, что это будет зависеть от операторов containerB и containerC в отношении того, как они используются в someFunction.

Все контейнеры шаблонные, но это не имеет значения, это проблема иерархии наследования.

Очень важно: поскольку явное преобразование типов определено для containerB и containerC, принимающих containerA в качестве аргумента, я мог бы передать containerC в качестве прямого аргумента myType::someFunction, но в этом случае происходит создание копии, а это именно то, чего я хочу избежать.

Некоторые конкретные примечания:

  • атрибуты как containerB, так и containerC точно такие же
  • someFunction использует только оператор [] для доступа к элементам контейнера и
  • оператор+= (но это определяется на уровне элемента шаблона)

containerB и containerC не являются двумя разными типами: containerC имеет только некоторые добавленные функции-члены, никакие внутренние данные объекта не изменяются.


person tmaric    schedule 25.11.2011    source источник


Ответы (3)


Нет, это небезопасно, и я бы предположил, что это относится к сфере неопределенного поведения.

Классы containerB и containerC — это вообще два разных типа (за исключением того, что они оба наследуют от containerA).

Таким образом, единственным «законным» способом вызова someFunction() для containerB и containerC будет

  • Предоставьте перегрузку someFunction, охватывающую типы
  • Обеспечить someFunction(containerA& ca) вместе с достаточным интерфейсом в базовом классе containerA
person cli_hlt    schedule 25.11.2011
comment
перегрузка пришла мне в голову, но есть ли безопасный способ использовать уже определенный код для someFunction(containerB)? - person tmaric; 25.11.2011
comment
если containerC и containerB имеют общие функциональные возможности, это должно быть выражено реализацией в containerA (от которого наследуются B и C) и затем может быть покрыто функцией someFunction, которая принимает containerA&. Если общего функционала нет, приходится иметь две разные реализации. Все остальное плохо. - person cli_hlt; 25.11.2011

Это совсем не безопасно.

someFunction, вероятно, вызовет метод, который является частью ContainerB (в противном случае он мог бы иметь ContainerA в качестве типа параметра).

Если этот метод вызывается для объекта, который не является ContainerB (потому что это ContainerC, вы только что привели его к типу), могут произойти плохие вещи (например, попытка доступа к несуществующим переменным-членам).

person Timbo    schedule 25.11.2011
comment
нет разных переменных-членов между containerB и containerC, someFunction вызывает оператор [] и выполняет арифметические действия над элементами (не зависит от этой проблемы) - person tmaric; 25.11.2011
comment
есть ли способ получить функциональность от someFunction(containerB) без переписывания кода? код точно, полностью, абсолютно одинаков для обоих контейнеров. - person tmaric; 25.11.2011

Как правило, это небезопасно, т.

  • containerB является containerA
  • containerC является containerA

из-за определения публичного наследования, но

  • containerB не containerC!

так что вы не можете просто перевести из одного типа в другой.

Возможно, стоит подумать о написании функции FromCtoB(...), которая копирует необходимые элементы из данного containerC в новый containerB.
Обратите внимание, что это возможно только в том случае, если соответствующие данные не объявлены private

person xmoex    schedule 25.11.2011