Upcast и Downcast в C ++ - PullRequest
       4

Upcast и Downcast в C ++

1 голос
/ 22 ноября 2011
class file {
    std::string name;
};

class directory : public file {
    std::vector<file*> entries;
};

directory d;
file f;

f = d; // Only d.name is copied to f; entries are lost

Это если мы сделаем это:

directory* dp = new directory;
file* fp ;

fp = dynamic_cast<file*>(dp); 

Сохраняет записи и идентификационные данные как объект каталога или все еще только dp->name копируется в f; записи потеряны.


Кроме того, как работает downcast?

Что произойдет, если мы сделаем:

dp = dynamic_cast<dp*> (fp);

Ответы [ 3 ]

3 голосов
/ 18 февраля 2013

Вот объяснение того, что является приведением вверх и вниз, взятым из ссылки: questionscompiled.com

Upcasting: Upcast - это преобразование указателя или ссылки типа производного класса в указатель илиссылка на тип базового класса, идущая вверх по дереву наследования.Upcasting помогает в достижении концепции интерфейсов в C ++.Когда функция вызывается по указателю или ссылке на тип базового класса (указывая или ссылаясь на некоторый из ее производного класса), вызывается правильная функция-член этого производного класса.

Downcasting: Downcast - преобразование указателя или ссылкитипа базового класса на указатель или ссылочный тип его производного класса, спускаясь вниз по дереву наследования.Это достигается с помощью оператора dynamic_cast, который безопасно понижает во время выполнения.

Вот пример:

class A
{public:
  int i;
  virtual void show(){}
};

class B:public A
{
public:
  int j;
  virtual void show()  { cout<<"B";  }
};

int main()
{
  A* ptr=new B; // UPCASTING
  B* ptrb;
  ptrb=dynamic_cast<B*>(ptr); //DOWNCASTING to derived object
  ptrb->show(); // upcasting helped in implementing interface
}

Применительно к приведенному выше примеру dynamic_cast гарантирует, что ptr указывает на объект типаB или его подкласс.

2 голосов
/ 22 ноября 2011

Я постараюсь объяснить просто, но вы все равно должны прочитать больше документации по этому вопросу.

directory d;
file f;

f = d; // Only d.name is copied to f; entries are lost

Это потому, что каталог и файл имеют разные типы и размеры. Файл имеет размер sizeof(file) и каталог sizeof(directory), который больше sizeof(file). Даже необработанная копия памяти только скопирует файловую часть каталога в файловый объект или выдаст неопределенное поведение, если вы намереваетесь копировать больше.

directory* dp = new directory;
file* fp ;

fp = dynamic_cast<file*>(dp); 

Во-первых, динамическое приведение здесь не будет работать, так как это не полиморфные типы. Если это так, это просто указатели. Поскольку каталог is-a file, вы можете указать каталог, используя указатель файла. Объект находится в этом соответствующем месте. Но у вас нет доступа к исключительным элементам каталога через указатель файла, если вы не откатились назад.

dp = dynamic_cast<dp*> (fp);

Вы восстанавливаете доступ члена каталога к исходному указателю, как описано выше.

1 голос
/ 22 ноября 2011

Наследование фиксирует отношения "есть". Учитывая контекст вашего вопроса, следующее не очень разумно:

class directory : public file

То, что имена каталогов и файлов имеют имена, не означает, что directory "is a" file. Также было бы неуместно говорить, что file "is a" directory.

Есть много других аргументов, которые вы могли бы здесь использовать. Например, вы можете утверждать, что как файлы, так и каталоги являются случаями thing_that_has_a_name:

class thing_that_has_a_name {
    std::string name;
    /* ... */
};

class file : public thing_that_has_a_name {
    /* ... */
};

class directory : public thing_that_has_a_name {
    std::vector<file*> entries;
    /* ... */
};

(Это один из способов решения этой проблемы, но наследование является довольно сложным механизмом. Если вы создаете базовые классы для таких вещей, как абстрактная концепция «иметь имя», то вы быстро обнаружите, что вам нужно наследовать от нескольких базовых классов.)

Чтобы вернуться к этим техническим аспектам того, на что вы смотрите, нужно помнить, что существует большая разница между созданием новых объектов и взаимодействием с существующий файл или объект каталога как thing_that_has_a_name. Если вы когда-нибудь сделаете заявление вроде:

directory d;
file f;

Это экземпляры. Конструкторы запускаются. Каким бы ни был sizeof каталог, именно столько памяти d только что получил. Каким бы ни был sizeof файл, вот что f только что получил. Однако:

thing_that_has_a_name& tthan_ref_to_d (d);
thing_that_has_a_name* tthan_ptr_to_f (&f);

Они просто создают ссылку и указатель, соответственно, через которые вы можете взаимодействовать с объектами каталога и файла через интерфейс, указанный в их базовом классе. Подобное «обновление» (называемое «вверх», потому что вы поднимаетесь по иерархии классов к корню) является относительно безопасным ... и не признаком того, что вы делаете что-то неправильно.

С другой стороны, «Даункинг» может быть опасным. Мы знаем, что каждый directory и file может рассматриваться как thing_that_has_a_name ... но если у вас есть указатель или ссылка на thing_that_has_a_name, то произвольный код не может быть уверен, что это directory или file. Есть способы вставить условный код, чтобы проверить и убедиться, но это часто считается признаком того, что вы делаете что-то не так в своем дизайне:

http://en.wikipedia.org/wiki/Run-time_type_information

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

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