views:

307

answers:

2

Hi, I'm working on a project and it's in a stage that I don't know what's wrong. Here's the simplified version:

The code:

    class Base {                   // This base class is pure abstract

    public:
        virtual ~Base();    // Necessary to trigger destructors in inherited classes
        virtual baseFunc() = 0;
    };



    class DerivedA : public Base{ 

    public:
        DerivedA(SomeClassUseBase * tmp){

         tmp -> register(this);
        }

        ~DerivedA();

        void baseFunc(){
            // do something here that's only for DerivedA        

       }
    };



    class DerivedB : public Base{ 

    public:

        DerivedB(SomeClassUseBase * tmp) {
              tmp -> register(this);
        }

        ~DeriveB();

        void baseFunc(){
            // do something here that's only for DerivedB        

       }
    };

     class SomeClassUseBase {

        private:
        Base ** basePrt;
        unsigned int index;

        public:
        someClassUseBase(int num) {

              basePrt = new Base*[num];   //create an array of pointers to the objects
              index = 0;
        }

        void register( Base * base ){

          //i tried *(basePrt[index]) = *base, but got the same problem
          basePrt[index] = base;  

          index = index + 1;  

        }

        void checkList() {
            for (int i = 0; i < index ;i++){
            next = basePrt[i];

                next -> baseFunc(); //fails here
        }
        }

   };

 int  main() {

    SomeClassUseBase tmp = new SomeClassUseBase(5);

    Base *b[5];

    for ( i = 0; i < 5; i += 1 ) {
        if ( i % 2 == 0 ) {
             b[i] = new DerivedA(&tmp);
        }
        else {

             b[i] = new DerivedB(&tmp);          
             // the object pointed by tmp::basePrt[0] is lost after this line
        } // if



    } // for

    tmp.checkList();       //crashes here since tmp.bastPrt[0] points to null

}

The problem is that when in main, i reach the line when the first DerivedB is created, the already created DerivedA pointer by tmp.basePrt[0] is lost some how. I don't know why but i suspect that this has sth to do with polymorphism? Please help!! thanks!!

Edit:

Didn't quite get the code correct the first time, sorry...

+3  A: 

Where is the closing bracket of the for loop?

void checkList() {
    for (int i = 0; i < index ;i++){
        next = basePrt[i];

        next -> baseFunc(); //fails here
    } // this one is missing in the example !

}


Use a vector ...

class SomeClassUseBase {

private:
    std::vector<Base*> basePrt;

public: 
    void register( Base * base ){
        basePrt.push_back(base);
    }

    void checkList() {
        std::for_each( basePrt.begin(), basePrt.end(), std::mem_fun(&Base::baseFunc);
    }

};


This works for me. It's not the code i would write for my projects but it works.

class SomeClassUseBase;

class Base {                   // This base class is pure abstract

public:
    virtual ~Base() {}    // Necessary to trigger destructors in inherited classes
    virtual void baseFunc() = 0;
};

class DerivedA : public Base { 

public:
    DerivedA(SomeClassUseBase * tmp){
        tmp -> registerIt(this);
    }

    void baseFunc(){
        // do something here that's only for DerivedA        
    }
};

class DerivedB : public Base {

public:
    DerivedB(SomeClassUseBase * tmp){
        tmp -> registerIt(this);
    }

    void baseFunc() {
        // do something here that's only for DerivedB        
    }
};

class SomeClassUseBase {

private:
    Base ** basePrt;  //Remark: use a vector or shared_array
    unsigned int index;  
    SomeClassUseBase(const SomeClassUseBase&);
    const SomeClassUseBase& operator=(const SomeClassUseBase&);
public:
    explicit SomeClassUseBase(int num) {
        //Remark: Store the size of the container 
        basePrt = new Base*[num];   //create an array of pointers to the objects
        index = 0;
    }

    ~SomeClassUseBase() {
        delete[] basePrt; 
    }
    void registerIt( Base * base ) {   
        //Remark: what if index >= size of the array?
        basePrt[index] = base;  
        index = index + 1;  

    }

    void checkList() const { 
        for (int i = 0; i < index ;i++){
            Base *next = basePrt[i];
            next->baseFunc();
        }
    }

};

int  main() {

    SomeClassUseBase tmp(5);
    Base *b[5];  //Remark: Use a smart_pointer
    for ( int i = 0; i < 5; i += 1 ) {
        if ( i % 2 == 0 ) {
            b[i] = new DerivedA(&tmp);
        }
        else {
            b[i] = new DerivedB(&tmp);          
        } // if
    } // for

    tmp.checkList();       

    for(int i = 0; i < 5; ++i ) {
        delete b[i]; 
    }
}
TimW
I added some additional info about why using array instead of vector, please check, thank you
derrdji
@derrdjii So why not return a vector of pointers instead of an array of pointers.
TimW
+4  A: 

You are creating the 5 Objects (DerivedA/B) in the Array Base* b[5], but in your checkList() you do not have access to those. Either try to get this array somehow into tmp or instantiate the DerivedA/B objects inside tmp.

In the current form, the two arrays within tmp and within main() are nowhere connected and that's why inside tmp you still have an empty array after running through main().

Update

Check also, that the type of the index (unsigned integer) member matches the type of your loop variable i (currently integer). Next try is to explicitely make your methods in the DerivedA/B also virtual (also the destructor!). Depending on the compiler this could be an issue that causes your call to baseFunc() still resolve to the Base's 'null' body. Finally, if it's really C++, you could try to work with references, so your constructors look like

DerivedA(SomeClassUseBase& tmp) {
  tmp.register(this);
}

Note the usage of the dot-operator instead of the '->', it makes things a bit easier to read and maintain.

Kosi2801
+1 Correct, tmp's SomeClassUseBase::register method is never called. Also, am assuming the line "SomeClassUseBase tmp = new SomeClassUseBase(5);" should be "SomeClassUseBase* tmp = new SomeClassUseBase(5);"
Binary Worrier
@Kosi2801: what do you mean by not having the access? are those just an array of pointers?
derrdji
SomeClassUseBase::register is called in the constructor of DerivedA and DerivedB, the other one is probably a typo?
Emile Vrijdags
Kosi2801
updated my answer for better readability
Kosi2801
@Kosi2801 Only the base class need the virtual key word. No compiler should choke on this.
TimW