capi1500
capi1500

Reputation: 115

c++ pointers to base class has not got derived class member functions but pointer is created with derived

I made class that is container for pointers to base class. I can add base class objects as well as derived class objects. However when I try to use functions from derived class objects I've got compilation error "'Base' class has not member named 'name'". Code looks like that:

    #include <cstdio>
    #include <vector>

    using namespace std;

    enum Type{
        obj,
        obj1,
        obj2
    };

    class Base{
        public:
            void fun(){
                printf("I'm base\n");
            }
    };

    class Derived1 : public Base{
        public:
            void fun2(){
                printf("I'm derived1\n");
            }
    };

    class Derived2 : public Base{
        public:
            void fun3(){
                printf("I'm derived2\n");
            }
    };

    class myVector{
        private:
            vector<Base*> objects;
        public:
            void add(Type type){
                switch(type){
                    case obj:
                        objects.push_back(new Base);
                        break;
                    case obj1:
                        objects.push_back(new Derived1);
                        break;
                    case obj2:
                        objects.push_back(new Derived2);
                        break;
                }
            }

            Base* operator[](unsigned index){
                return objects[index];
            }
    };

    int main(){
        myVector vec;
        vec.add(obj);
        vec.add(obj1);
        vec.add(obj2);
        vec[0]->fun();     // ok
        vec[1]->fun1();    // error "Base" has not member named "fun1"
        vec[2]->fun2();    // error "Base" has not member named "fun2"
    }

It should print

I'm base
I'm derived1
I'm derived2

but I've got compilation error like in code in comments

Upvotes: 1

Views: 1640

Answers (3)

BartekPL
BartekPL

Reputation: 2420

You just should make it a virtual function and override it in the derived class

#include <cstdio>
#include <vector>

using namespace std;

enum Type{
    obj,
    obj1,
    obj2
};

class Base{
    public:
        virtual void fun(){
            printf("I'm base\n");
        }
};

class Derived1 : public Base{
    public:
        void fun(){
            printf("I'm derived1\n");
        }
};

class Derived2 : public Base{
    public:
        void fun(){
            printf("I'm derived2\n");
        }
};

class myVector{
    private:
        vector<Base*> objects;
    public:
        void add(Type type){
            switch(type){
                case obj:
                    objects.push_back(new Base);
                    break;
                case obj1:
                    objects.push_back(new Derived1);
                    break;
                case obj2:
                    objects.push_back(new Derived2);
                    break;
            }
        }

        Base* operator[](unsigned index){
            return objects[index];
        }
};

int main(){
    myVector vec;
    vec.add(obj);
    vec.add(obj1);
    vec.add(obj2);
    vec[0]->fun();     // ok
    vec[1]->fun();     // now it works
    vec[2]->fun();     // now it works
}

Upvotes: 2

Toby Speight
Toby Speight

Reputation: 30831

If you want to be able to call methods through a base-class pointer, then those methods need to be defined in the base class (perhaps as pure virtual methods).

If you know you have a subclass object, you may want to static_cast (or perhaps dynamic_cast and test), and call the method through the cast pointer.

Without any knowledge of the semantics of fun1() and fun2() it's impossible to know which alternative is best for your situation.

Here's a version that does what you want - note that Base::fun is declared virtual and the subclass implementations override it.

#include <iostream>
#include <vector>

struct Base {
    virtual void fun() const {
        std::cout << "I'm base" << std::endl;
    }
    virtual ~Base() = default;
};

struct Derived1 : public Base{
    void fun() const override {
        std::cout <<  "I'm derived1" << std::endl;
    }
};

struct Derived2 : public Base{
    void fun() const override {
        std::cout << "I'm derived2" << std::endl;
    }
};

int main(){
    std::vector<Base*> vec{new Base(), new Derived1(), new Derived2()};
    vec[0]->fun();
    vec[1]->fun();
    vec[2]->fun();

    // cleanup
    for (auto e: vec)
        delete e;
}

Upvotes: 1

Edward Strange
Edward Strange

Reputation: 40859

C++ resolves names statically, at compile time. You told it you have a Base*. Those are the names you're allowed to use on that object, through that pointer. Want access to the ones in Derived you'll have to cast.

Upvotes: 2

Related Questions