апскейтинг и доткастинг в C ++ - PullRequest
0 голосов
/ 26 апреля 2018

Я пробовал идею приведения в C ++ с использованием Visual Studio C ++ 2010 Express и использования dynamic_cast.Но каким-то образом, когда я запускаю его, объект cat может фактически выполнять поведение собаки.

Похоже, Dog d = (Dog ) aa; запутал компилятор.Любой совет?

Ниже мой код.

`
#include <iostream>
#include <string>

using namespace std;

class Animal {
public:
    string name ;
    Animal(string n) : name(n) {cout << "construct animal " << name << endl ;  }
    Animal() : name("none") { };
    virtual string getName() { return name ; }
    virtual ~Animal() { cout << "destruct animal " << name << endl ; }
};

class Dog: public Animal{

public:
    Dog() :Animal("") { }
    Dog(string n): Animal(n) {
        cout << "construct Dog" << endl ; 
    }
    void dogStuff() { cout << "hello woof...."; }
};

class Cat: public Animal{

public:
    Cat() :Animal("") { }
    Cat(string n): Animal(n) {
        cout << "construct Cat" << endl ; 
    }
    void catStuff() { cout << "hello meow...."; }
};

int main() { 

    Animal *aa = new Cat("Catty"); // cat upcasting to animal 
    Dog *d = (Dog*)aa; // animal downcasting to dog. ???
    cout << d->getName() << endl;
    d->dogStuff();
    Dog* dog = dynamic_cast<Dog*>(d) ;

    if(dog)  { 
        cout << "valid  cast" << endl ;
        dog->dogStuff();
        cout << dog->getName();
    }else
        cout << "invalid  cast" << endl ;

    int i ;
    cin >> i ;

    return 0;
}

выход

конструкция животного Catty

конструкция Cat

Catty

привет ....действительный актерский состав

привет гав ... Кэтти

`

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018
Dog *d = (Dog*)aa;

Стиль приведения типа в круглых скобках называется приведением в стиле C , поскольку он предназначен для имитации поведения C. В этом случае компилятор выполняет static_cast, чтопереходит к понижению Animal* до Dog*, исходя из предположения , что базовым объектом является Dog.Поскольку базовый объект на самом деле Cat, программа плохо сформирована, и может произойти все что угодно, включая повреждение памяти.Приведения в стиле C никогда не выполняют никаких проверок безопасности во время выполнения.

Dog* dog = dynamic_cast<Dog*>(d);

На самом деле это приведение не должно ничего делать: оно преобразуется из Dog* в Dog*.Проверка безопасности во время выполнения не требуется, даже если используется dynamic_cast, поскольку предполагается, что d является правильно сформированным Dog*.

Совет

Избегайте бросков в стиле C.Убедитесь, что все откаты действительны.Лично я не очень много пользуюсь dynamic_cast, но тогда я несу ответственность только за то, чтобы опускать руки должным образом.

0 голосов
/ 26 апреля 2018
Animal *aa = new Cat("Catty"); // cat upcasting to animal 
Dog *d = (Dog*)aa; // animal downcasting to dog. ???

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

Dog* dog = dynamic_cast<Dog*>(d);

Поскольку d уже является Dog *, компилятор, вероятно, не генерирует код для выполнения RTTI, а просто присваивает его, следовательно, это успешно.

...