Должен ли я использовать Dynamic_cast<T> для копирования?

StackOverflow https://stackoverflow.com/questions/733537

  •  06-09-2019
  •  | 
  •  

Вопрос

Обновление 1:

Исправлен бредовый код!Спасибо за комментарии, я сделал хеш из первого фрагмента, упс.

Обновление 2:

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

Здесь я пытаюсь добиться глубокого копирования с использованием строгих типов;Я хочу иметь возможность скопировать Class2 в другой экземпляр Class2;однако я также хочу использовать функцию CopyTo из класса Class1, который является базовым.Эта идея исходит из моего опыта работы с C#, когда обычно я просто делал тип возвращаемого значения универсальным (см. фрагмент кода C#).

void Class1::CopyTo(Class1 *c1)
{
    // Write data in to c1 from this instance.
    c1->exampleData = exampleData;
}

// Class2 inherits Class1
Class2 *Class2::Copy()
{
    Class2 *c2a = new Class2();
    CopyTo(c2a);

    Class2 *c2b = dynamic_cast<Class2*>(c2a);
    return c2a;
}

И вот как я это сделал бы на C#:

public class Class1
{
    T Copy<T>()
        where T : Class1
    {
        /* Can't remember the best way to do this in C#;
         * basically if T was Class2 this would need to create
         * a new instance of that class, and the same goes for
         * Class1. */         
        T copy = createNewInstance();

        // Copy the data from this to 'copy'.
        copy.exampleData = exampleData;

        return copy;
    }
}

Теперь, по сравнению с фрагментом C#, фрагмент C++ кажется вонючим.Можно ли сделать это без указателей или это лучшая практика?

Это было полезно?

Решение

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

template <typename T>
T Class1::Copy()
{
    T instance;
    CopyTo(&instance);
    return instance;
}

Это работает, потому что вы передаете (полиморфный) указатель на instance к CopyTo метод Class1.

Тогда вы можете вызвать код следующим образом:

Class2 x1;
// Fill x1
Class2 x2 = x1.Copy<Class2>();

Однако этот код все еще пахнет, потому что это не идиоматический C++:В C++ вместо этого обычно пишут конструктор копирования.Позднее прибытие Copy методы существуют, но они необходимы очень редко, и приведенное выше не является поздней привязкой (но и ваш код C# тоже).

Другие советы

Я не понимаю, о чем вы спрашиваете, но имейте в виду, когда вы говорите:

 Class2 *c2 = dynamic_cast<Class2*>(c1);

результат приведения может быть NULL, и вы должны это проверить.

Вам следует еще немного поработать над фрагментом кода.GetSomethingCopy создает указатель типа Class2, который передается в CopyTo.CopyTo пытается вызвать функцию-член полученного указателя, который никогда не был инициализирован:ошибка сегментации и программа умирает.

Даже если это не убило приложение, вы пытаетесь динамический_cast из класса 2* в класс 2*, что практически ничего не делает.Если вы намереваетесь привести возвращаемое значение из CopyTo, вы должны знать, что вы не можете использовать Dynamic_cast для void*.Вы должны либо изменить подпись CopyTo, чтобы вернуть Class1 (чтобы вы могли позже его привести), либо использовать static_cast для void*.

Обратите внимание, что либо Copy — это виртуальная функция в классе 1, которая фактически выполняется в классе 2 и создает объект класса 2, либо возвращаемый элемент будет не классом 2, а скорее классом 1.

Название метода CopyTo сбивает с толку, поскольку оно не копирует к аргумент, а скорее из аргумента.

И после всего этого я до сих пор не понимаю, о чем вы спрашиваете.Где бы вы хотели использовать стековую память?Вы можете передать элемент, выделенный в стеке, в функцию, но возврат указателя/ссылки на элемент, выделенный в стеке, снова является ошибкой сегментации:объект будет уничтожен, когда функция завершится, и у получателя останется висячий указатель/ссылка.

Теперь, если ваш вопрос более теоретический о том, можете ли вы использовать Dynamic_cast для элемента, выделенного в стеке, вы можете (при условии, что Class2 наследует от Class1):

void f()
{
   Class2 c2;
   Class1 &c1 = c2; // c1 is a Class1 reference to a Class2 object

   dynamic_cast<Class2&>(c1).class2method(); 
   // or:
   dynamic_cast<Class2*>(&c1)->class2method();
}

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

этот код не имеет смысла, как указано...в любом случае, я «думаю», вы могли бы использовать статическое приведение, если бы вы не использовали void* в качестве возврата?

Хорошо, теперь код имеет смысл.

Вам не нужно никакого динамического приведения, оно уже имеет тип Class2.

В вашей функции CopyTo вы будете возвращать указатель на объект, который был создан в стеке — это невозможно, поскольку объект, на который указывает указатель, будет уничтожен при возврате функции.

В ответ на ваш вопрос вы можете использовать dynamic_cast по указателю или ссылке.В вашем случае я мог бы выделить объект, который будет возвращен динамически, используя new а не в стеке, то вы можете безопасно вернуть указатель.Однако я склонен использовать dynamic_cast как потенциальный запах кода и признак того, что следует использовать виртуальную функцию.

Нет, динамический_cast работает только с указателями и ссылками.В любом случае вы не сможете безопасно вернуть все, что разместили в стеке, поэтому я не уверен, как вы собирались изменить свой код в этом случае.

Ах, теперь проблема ясна.Технически ответ — нет, не с помощью Dynamic_cast<>, но я действительно не понимаю, зачем вам это нужно.Кажется, ты просто хочешь

void Class1::CopyTo(Class1& c1)
{
    // Write data in to c1 from this instance.
    c1.SomeIntValue = SomeIntValue;
}

// Class2 inherits Class1
Class2* Class2::Copy()
{
    Class2 *c2 = new Class2();
    CopyTo(*c2);
    return c2;
}
//or more idiomatic
Class2 Class2::Copy()
{
    Class2 c2
    CopyTo(c2);
    return c2;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top