Hello guys,

This project requires the use of an array of pointers to aRandomNumberGenerator (i'll call it Random for short) objects. Both aDie and aCoin are derived classes of the Random class. I am to use the array to call the virtual function generate. My problem arises in my main class when I try to use the array of pointers to generate numbers for a coin and a die.

Every time I run this program it just crashes, this happened after I added the downcasting statements. I am stuck on this and I have no idea why. Is there another way of doing this without downcasting? Any help is appreciated and thanks in advanced!

#include <iostream>
#include "aDie.h"
#include "aCoin.h"
#include "aRandomNumberGenerator.h"

using namespace std;

int main()
{    
    aRandomNumberGenerator* array[2];
    array[0] = new aCoin();
    array[1] = new aDie();
    
    aCoin* cDerivedPtr = dynamic_cast <aCoin *> (array[0]);
    aDie* dDerivedPtr = dynamic_cast <aDie *> (array[1]);
    
    int cTest[2];
    int dTest[6];
    
    int x = 0; //Variable that stores the return value of coin generate 
    int y = 0; //Variable that stores return value of dice generate
    
    int s;
    cout << "Please insert a seed value for both generators: ";
    cin >> s;
    
    cDerivedPtr->seed(s);
    dDerivedPtr->seed(s);

    for(int i = 0; i < 600; i++)
    {
        x = cDerivedPtr->generate();
        cTest[x]++;
        
        y = dDerivedPtr->generate();
        dTest[y-1]++;
    }
    
    cout << "Heads: " << cTest[0] << "\n";
    cout << "Tails: " << cTest[1] << "\n";

    cout << "1: " << dTest[0] << "\n";
    cout << "2: " << dTest[1] << "\n";
    cout << "3: " << dTest[2] << "\n";
    cout << "4: " << dTest[3] << "\n";
    cout << "5: " << dTest[4] << "\n";
    cout << "6: " << dTest[5] << "\n";       
    
    cin.get();  //Stops window from closing
    cin.get(); 
    return 0;
}

Recommended Answers

All 14 Replies

You should always test, after you use dynamic_cast, whether the returned pointer is NULL. In this case it shouldn't though, so back to square one.

This is not polymorphism (at least not what it usually refers to), you're not supposed to have to perform a dynamic_cast just to call a few virtual functions. Are your functions "seed" and "generate" virtual? Can you show the class declarations of all three classes?

Otherwise, I don't see anything wrong with the code.

Ok, here are the header files for the classes. When I started this I did not use dynamic_cast, but it still crashed. What I originally did was use the array to access the members, ie: array[0]->generate, but it also crashed that way.

#ifndef RANDOM_H
#define RANDOM_H

class aRandomNumberGenerator
{
    public:
        aRandomNumberGenerator(); //Constructor
        aRandomNumberGenerator(int value);
        virtual double generate();  //Generates a random number
        void setSeed(int value); //Sets the seed value
        ~aRandomNumberGenerator(); //Destructor
        
    private:
        int seed; //Member variable that stores the seed value
};

#endif


#ifndef DIE_H
#define DIE_H

#include "aRandomNumberGenerator.h"

class aDie: public aRandomNumberGenerator
{
    public:
        aDie();
        double roll(); //Return a number between 1-6 based on a random value
        void seed (int s); //Seeds the generator
        int inputSeed(); //Asks user for input seed and seeds the generator
        virtual double generate(); //Generates a random number between 1 and 6
        virtual ~aDie();

};

#endif



#ifndef COIN_H
#define COIN_H

#include "aRandomNumberGenerator.h"

class aCoin: public aRandomNumberGenerator
{
    public:
        aCoin();
        double flip(); //Return 1 or 0 based on a random value
        int inputSeed(); //Asks user for input seed and seeds the generator
        void seed (int s); //Seeds the generator
        virtual double generate(); //Generates a random number between 1 and 6
        virtual ~aCoin();
};

#endif

First of all, you should post the code for your classes so we can see the underlying logic.

Secondly, you really don't need to do any casting here. Because the generate() function (I assume) is a virtual member of your base class, you should be able to call ptr->generate() with any pointer to any derived instance of your base class.

Here's some example code showing this concept:

#include <iostream>
#include <vector>

using namespace std;

class Base
{
public:
    virtual ~Base(){}
    virtual string name()
    {
        return "Base";
    }
};

class Derived0 : public Base
{
public:
    virtual ~Derived0(){}
    virtual string name()
    {
        return "Derived0";
    }
};

class Derived1 : public Base
{
public:
    virtual ~Derived1(){}
    virtual string name()
    {
        return "Derived1";
    }
};

int main(int argc, char *argv[])
{
    Base* arr[3];
    arr[0] = new Derived0();
    arr[1] = new Derived1();
    arr[2] = new Base();
    for( int i=0; i<3; i++ )
        cout << "arr[" << i << "]->name(): " << arr[i]->name() << endl;
    return 0;
}

The real key here is understanding inheritance. If you have a container that can hold pointers to different derived classes, you probably don't want to have to keep track of what kind of class to which each pointer refers. Inheritance allows you to have many different kinds of classes that all use some basic interface. This way, you can use many similar but different objects in identical ways. Dynamic casting has its uses, but it is not necessary to take advantage of the benefits of using containers that hold pointers to many different derived classes.

I'd like to point out another problem. If your random number generators use the rand() function, you need to be careful how you seed the generator. You should not use srand() more than once! The srand() function gives the rand() function a starting point, and all subsequent calls to rand() will provide a pseudo random distribution of integers in the range 0 to RAND_MAX; The srand() seeder and rand() generator use some global variables. You can't create multiple instances of the generator, so all calls to srand() reseed the same random number generator. If you have many instances of a class that all call rand(), they are using the same RNG. The srand() function should be called only once, and it should be early in the life of the program. You can either do this explicitly by calling srand(time(0)) early in your main() function, or you could use a static member of your base RNG class. Here's how you could do that:

class BaseRNG
{
private:
    // A flag indicating if srand() has been called
    // Shared by all instances of RNG in the current program
    static bool seeded;

public:
    /** Constructs a rand master */
    BaseRNG()
    {
        if( seeded == false )
        {
            seeded = true;
            srand( time(0) );
        }
    }
};

bool BaseRNG::seeded = false;

Using this method, srand() will only be seeded once, and it will be seeded with a value that is unique each time you run the program.

I'm not sure if this is the source of the crash, but you should have a virtual seed() function in the base class and the destructor in the base class needs to be virtual as well. the data member "seed" in the base class should be in the "protected" scope not in "private" scope. Try that and see if it helps.

Ah yes, sorry about that. Here are the implementations. Okay I think I see what you're saying. But wouldn't i still need to downcast it to access the derived-specific function seed? Unless I had a constructor that seeded the generator I need a way to access the seed function.

#include <iostream>
#include <ctime>
#include <cstdlib>
#include "aRandomNumberGenerator.h"

using namespace std;

aRandomNumberGenerator::aRandomNumberGenerator()
{
    setSeed(time(NULL));
}

aRandomNumberGenerator::aRandomNumberGenerator(int value)
{
    setSeed(value);
}

aRandomNumberGenerator::~aRandomNumberGenerator()
{
    //In this case, the destructor does nothing.   
}

double aRandomNumberGenerator::generate()
{
   return (rand() % 101);
}

void aRandomNumberGenerator::setSeed(int value)
{
    seed = value;
    srand(seed);
}


#include <iostream>
#include "aDie.h"
#include <cmath>
using namespace std;

aDie::aDie()
{
   //Constructor does nothing.
}

double aDie::roll()
{   
    return generate();
}

double aDie::generate() 
{
    return (fmod(aRandomNumberGenerator::generate(), 6) + 1);   
}

void aDie::seed(int s)
{
    aRandomNumberGenerator::setSeed(s);
}

int aDie::inputSeed()
{
    int value;
    
    cout << "Please enter a seed value for the dice: ";
    cin >> value;
    
    seed(value);
    
    return value;
}

aDie::~aDie()
{
    //Destructor does nothing in this case.
}


#include "aCoin.h"
#include <iostream>
#include <cmath>

using namespace std;

aCoin::aCoin()
{
    //Constructor does nothing.
}

double aCoin::flip()
{
    return generate();
}

double aCoin::generate()
{
    return (fmod(aRandomNumberGenerator::generate(), 2));  
}

int aCoin::inputSeed()
{
    int value;
    
    cout << "Please enter a seed value for the coin: ";
    cin >> value;
    
    seed(value);
    
    return value;
}

void aCoin::seed (int s) 
{
    aRandomNumberGenerator::setSeed(s);
}

aCoin::~aCoin()
{
    //Destructor does nothing in this case.
}

All your seed() functions are just calling setSeed() from the base class. Just call setSeed() directly in your main function or replace setSeed in the base class by a virtual seed function. With that, no you don't need to cast.

MAKE YOUR BASE CLASS DESTRUCTOR VIRTUAL!! That's paramount before anything else.

Also, you already have a constructor that seeds the random number generator, the constructor of aRandomNumberGenerator.

I just attempted the changes you mentioned and it still crashes. I just changed my main to try and isolate the problem, and it always crashes whenever the line array[0]->generate() is there. I am baffled as to why this happens... I made generate virtual and use a base pointer.

I also made the destructor virtual in the base class.

int main()
{    
    aRandomNumberGenerator* array[2];
    array[0] = new aCoin();
    array[1] = new aDie();
    
    int cTest[2];
    int dTest[6];
    
    int x = 0; //Variable that stores the return value of coin generate 
    int y = 0; //Variable that stores return value of dice generate

    cout << array[0]->generate();
}

Please read the end of my previous post.

You should not call srand() more than once each time you execute the program. That is why I reccommended adding the srand() call to the constructor of the base class, and protecting this with a static boolean flag so that it is only executed once. Alternatively, you could call srand() at the beginning of your main function.

Calling srand() multiple times, even if it is within the scope of two separate classes in two separate files, re-seeds the same random number generator. The generator only needs to be seeded once per instance of your program.

This isn't why your program is crashing, but it is a critical logic error.

Please post the error output. Is it just a segmentation fault?

I get no errors, I run it and a window appears saying "Polymorphism.exe has stopped working." Don't know if it is relevant, but I am using Dev-C++.

There are still some problems.

First of all, I don't know why your generate() functions are returning doubles. Neither a Die or a Coin use floating point values. They both return integers. The rand() function also returns integers. There is no need for returning doubles or using the fmod function. I would change your genereate functions to return integers and use the % operator instead. Try this, and see how it goes.

I get no errors, I run it and a window appears saying "Polymorphism.exe has stopped working." Don't know if it is relevant, but I am using Dev-C++.

In this case, you should put in some lines that print debugging information. Try adding lines around the part that you think is causing problems. Here is an example

int someVal=10;
    cout << "someVal == " << someVal;
    someVal = someTroublesomeFunction( someVal );
    cout << "someVal == " << someVal;

This will let you know where you are crashing and what the values of different variables are at the time of the crash.

Yeah, it's relevant! Dev-C++ is outdated and produces erroneous code on windows version Vista and newer. Use code::blocks instead.

I copied your code and compiled it on linux and I never got errors even with all the original issues that I though _might_ cause the error. So.. yeah it's relevant that you used Dev-C++!

There are still some problems.

First of all, I don't know why your generate() functions are returning doubles. Neither a Die or a Coin use floating point values. They both return integers. The rand() function also returns integers. There is no need for returning doubles or using the fmod function. I would change your generate functions to return integers and use the % operator instead. Try this, and see how it goes.

Every single class within this project was also a previous project, and I'm supposed to use those previous projects as they are. Yes I understand what you mean and I also directed that issue to my professor, who just expect us to follow the specifications he provides us with.

Ah I see mike, I'll try compiling it on linux and see what I get.

Indeed... you are right, it does work on other IDE's and on Linux... Thanks so much for your help and sorry for wasting your time on a working program...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.