0

Having this example code here:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>

namespace autos
{
    enum CarTypes
    {
        SUVType,
        SportType,
        UnknownType
    };

    class Car
    {
        public: 
            Car();
            virtual ~Car();

            CarTypes type;
            int powerCV;
    };

    Car::Car()
    {
        type = CarTypes::UnknownType;
    }

    Car::~Car() {}

    class SUV : public Car
    {
        public: 
            SUV();
            virtual ~SUV();

            bool fourXFour;
            int  trunkSizeLiters;
            bool dvdInBackSeat;
    };

    SUV::SUV() 
    {
        type = CarTypes::SUVType;
        powerCV = 0;
        fourXFour = false;
        trunkSizeLiters = 0;
        dvdInBackSeat = false;
    }

    SUV::~SUV() {}

    class Sport : public autos::Car
    {
        public:
            Sport();
            virtual ~Sport();

            bool convertible;
            bool twoSeats;
            int  maxSpeed;
    };

    Sport::Sport() 
    {
        type = autos::CarTypes::SportType;
        powerCV = 0;
        convertible = false;
        twoSeats = false;
        maxSpeed = 0;
    }

    Sport::~Sport() {}
} /* end namespace autos */


autos::Car ManufactureCar()
{
    srand(time(NULL));
    int typeCode = rand() % 2 + 1;

    if (typeCode == 1)
    {
        autos::SUV newSUV;
        newSUV.powerCV = 300;
        newSUV.fourXFour = true;
        newSUV.trunkSizeLiters = 500;
        newSUV.dvdInBackSeat = true;
        return newSUV;
    }

    autos::Sport newSport;
    newSport.powerCV = 550;
    newSport.maxSpeed = 300;
    newSport.twoSeats = true;
    newSport.convertible = true;
    return newSport;
}

int main(int argc)
{
    autos::Car newCar = ManufactureCar();

    if (newCar.type == autos::CarTypes::SportType)
    {
        std::cout << "A new SPORT car was manufactured: " << std::endl;

        autos::Sport& sportCar = dynamic_cast<autos::Sport&>(newCar);

        std::cout << "Power (CV): " << sportCar.powerCV << std::endl;
        std::cout << "Convertible: " << sportCar.convertible << std::endl;
        std::cout << "Maximum speed: " << sportCar.maxSpeed << std::endl;
        std::cout << "Two seats: " << sportCar.twoSeats << std::endl;
    }
    else if (newCar.type == autos::CarTypes::SUVType)
    {
        std::cout << "A new SUV car was manufactured: " << std::endl;

        autos::SUV& suvCar = dynamic_cast<autos::SUV&>(newCar);

        std::cout << "Power (CV): " << suvCar.powerCV << std::endl;
        std::cout << "4x4: " << suvCar.fourXFour << std::endl;
        std::cout << "Trunk size (Liters): " << suvCar.trunkSizeLiters << std::endl;
        std::cout << "DVD in backseats: " << suvCar.dvdInBackSeat << std::endl;
    }
    else
    {
        std::cout << "ERROR: Unknown car manufactured." << std::endl;
    }

}

I´ve looked at this post here and the program shown compiles, but it does throw an exception (Access violation) when the dynamic_cast is called.... I´ve tried using pointers: autos::SUV* suvCar = dynamic_cast<autos::SUV*)(&newCar) and got also access violation.

Why am I´m not being able to cast the data to the derived type ?

Is there a better way to get the real type or dynamic_cast is the only/better option here ?

[EDIT - SOLUTION]

Problem solved using smart pointers:

std::shared_ptr<autos::Car> ManufactureCar()
{
    srand(time(NULL));
    int typeCode = rand() % 2 + 1;

    if (typeCode == 1)
    {
        autos::SUV newSUV;
        newSUV.powerCV = 300;
        newSUV.fourXFour = true;
        newSUV.trunkSizeLiters = 500;
        newSUV.dvdInBackSeat = true;

        auto ret = std::make_shared<autos::SUV>(newSUV);
        return std::dynamic_pointer_cast<autos::Car>(ret);
    }

    autos::Sport newSport;
    newSport.powerCV = 550;
    newSport.maxSpeed = 300;
    newSport.twoSeats = true;
    newSport.convertible = true;

    auto ret = std::make_shared<autos::Sport>(newSport);
    return std::dynamic_pointer_cast<autos::Car>(ret);
}

int main(int argc)
{
    std::shared_ptr<autos::Car> newCar = ManufactureCar();

    if (newCar->type == autos::CarTypes::SportType)
    {
        std::cout << "A new SPORT car was manufactured: " << std::endl;

        std::shared_ptr<autos::Sport> sportCar = std::dynamic_pointer_cast<autos::Sport> (newCar);

        std::cout << "Power (CV): " << sportCar->powerCV << std::endl;
        std::cout << "Convertible: " << sportCar->convertible << std::endl;
        std::cout << "Maximum speed: " << sportCar->maxSpeed << std::endl;
        std::cout << "Two seats: " << sportCar->twoSeats << std::endl;
    }
    else if (newCar->type == autos::CarTypes::SUVType)
    {
        std::cout << "A new SUV car was manufactured: " << std::endl;

        std::shared_ptr<autos::SUV> suvCar = std::dynamic_pointer_cast<autos::SUV> (newCar);

        std::cout << "Power (CV): " << suvCar->powerCV << std::endl;
        std::cout << "4x4: " << suvCar->fourXFour << std::endl;
        std::cout << "Trunk size (Liters): " << suvCar->trunkSizeLiters << std::endl;
        std::cout << "DVD in backseats: " << suvCar->dvdInBackSeat << std::endl;
    }
    else
    {
        std::cout << "ERROR: Unknown car manufactured." << std::endl;
    }

}
Community
  • 1
  • 1
Mendes
  • 17,489
  • 35
  • 150
  • 263
  • 2
    Your object is getting [sliced](http://stackoverflow.com/q/274626/2069064) – Barry Mar 21 '16 at 15:48
  • Argh... never heard about this... no idea how to solve that... – Mendes Mar 21 '16 at 16:01
  • 1
    instead of returning a copy, allocate the object on the heap and return the pointer/reference from your ManufacturCar factory. That way the copy constructor is not called, either that or create copy constructors for your classes – AndersK Mar 21 '16 at 16:07

1 Answers1

1

Where you have autos::Car newCar = ManufactureCar(); in your program, you are allocating only enough storage for a Car object. You can't cast that to a subclass that takes more storage.

I suggest you modify your ManufactoreCar() function to create the appropriate object on the heap and return a pointer to that object.

For example,

   if (typeCode == 1)
    {
        autos::SUV* x = new autos::SUV;
        x->powerCV = 300;
        x->fourXFour = true;
        x->trunkSizeLiters = 500;
        x->dvdInBackSeat = true;
        return x;
    }

Then your objects will already have been allocated properly for their types. Of course, you would also use pointers to refer to them later in your program. I hope this helps.

Logicrat
  • 4,438
  • 16
  • 22
  • I got your point and thanks for the info. I´m thinking in a way to do this avoiding the use of `new` and `delete` statements, as these for me are synonimous of "you are not using the good practices"... Maybe `std::shared_ptr ManufactureCar()`has a good usage here... – Mendes Mar 21 '16 at 16:22
  • `new` and `delete` are not necessarily bad practice, especially if your program is using polymorphism, which it is, by using an object that may represent any of several different types. – Logicrat Mar 21 '16 at 16:29
  • Solved using smart pointers. Check the EDIT. Thanks for helping. – Mendes Mar 21 '16 at 16:39