Должен ли я использовать dynamic_cast <T>для копирования? - PullRequest
0 голосов
/ 09 апреля 2009

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

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

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

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

То, чего я пытаюсь достичь, это глубокая копия с использованием сильных типов; Я хочу иметь возможность скопировать 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 ++ выглядит вонючим. Можно ли сделать это без указателей, или это лучший способ?

Ответы [ 7 ]

1 голос
/ 09 апреля 2009

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

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

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

Название метода 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();
}

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

1 голос
/ 09 апреля 2009

Мне не понятно, о чем вы спрашиваете, но помните, что когда вы говорите:

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

результат приведения может быть НЕДЕЙСТВИТЕЛЕН, и вы должны проверить это.

0 голосов
/ 09 апреля 2009

Ах, теперь проблема ясна. Технически нет, не с 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;
}
0 голосов
/ 09 апреля 2009

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

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 #).

0 голосов
/ 09 апреля 2009

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

0 голосов
/ 09 апреля 2009

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

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

0 голосов
/ 09 апреля 2009

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

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

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

...