2

I know in C# there is a way to make a variable take in values so long as they share a base class, but I'm stumped with C++. Is what I am trying to do possible?

This is what my code looks like:

class BaseClass
{
    public:
        virtual void Setup() = 0;       
        virtual void DisplayText() = 0;
};

class A: public BaseClass
{
    public:     
        void Setup();       
        void DisplayText();
};

class B: public BaseClass
{
    public:     
        void Setup();       
        void DisplayText();
};


//main.cpp

A a;
B b;

std::vector<BaseClass> vector = std::vector();

void main()
{
    vector.push_back(a);
    vector.push_back(b);

    for_each (vector.begin(), vector.end(), vector.Setup());

    return 0;
}

With what I have right now though it is giving me this error when I try running this:

IntelliSense: no instance of overloaded function
"std::vector<_Ty,_Alloc>::push_back [with _Ty=BaseClass,,Alloc=std::allocator<BaseClass>]"
matches the argument list
argument types are: (A*)
object type is: std::vector<BaseClass, std::allocator<BaseClass>>
Barry
  • 286,269
  • 29
  • 621
  • 977

3 Answers3

7

There's a lot wrong here. First:

std::vector<BaseClass> vector = std::vector();

That's invalid syntax, vector is not a type so you can't create one like you do on the right hand side. Just this is sufficient:

std::vector<BaseClass> vector;

Second, this is not how you call for_each:

for_each (vector.begin(), vector.end(), vector.Setup());

There is no Setup() function on vector. And if there was, that's not even the Setup you wanted to call. What you want to use is std::mem_fun:

for_each (vector.begin(), vector.end(), std::mem_fn(&BaseClass::Setup));

Once we get there, then we get to the major problem in your code: you're slicing all of your objects! Well, first, we're trying to store abstract classes in a vector by value, which is not possible. And if it was, it wouldn't do what you wanted anyway because of the slicing issue. What you need to do is change your vector to store pointers to BaseClass instead:

std::vector<BaseClass*> vector;
vector.push_back(&a);
vector.push_back(&b);

And then, and only then, will your code compile. Well, assuming you provide definitions for your virtual overrides somewhere - otherwise it won't link.

Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977
  • Would it be possible to use a reference for the typename given to the vector? – Mark Feb 09 '15 at 00:38
  • 2
    @Mark You mean `vector`? No. The element type must be assignable. – Barry Feb 09 '15 at 00:39
  • @Barry I have most of what you wrote implemented now. I need to make a change though. I want to have the vector in my base class as a static value and i need to call it in my main. The problem though is it is giving me this linker error: error LNK2001: unresolved external symbol "public: static class std::vector > BaseClass::vector" (?s_Screens@GameScreens@@2V?$vector@PAVGameScreens@@V?$allocator@PAVGameScreens@@@std@@@std@@A) How do I resolve it? – SyntaxIsEvil Feb 09 '15 at 02:09
  • 1
    @SyntaxIsEvil [What is an unresolved external symbol error?](http://stackoverflow.com/q/12573816/2069064) – Barry Feb 09 '15 at 02:16
  • 1
    @Barry I forgot to initialize my vector in my main. It all works perfectly. Thank you so very much for your help! – SyntaxIsEvil Feb 09 '15 at 02:26
  • @Barry I seem to have 1 more issue. I have a virtual function in my BaseClass that take in values (virtual void Key(int key, int x, int y)). How would I get this to work with my for_each? If I set it up like I did with my other for_each loops it gives me this error: error C2064: term does not evaluate to a function taking 1 arguments . If I add the arguments then it gives this error: 3 IntelliSense: no instance of overloaded function "std::mem_fn" matches the argument list argument types are: () – SyntaxIsEvil Feb 09 '15 at 19:26
  • @SyntaxIsEvil One question per question! Ask a new question. – Barry Feb 09 '15 at 19:58
4

Yes, it is doable. You need to change your vector to hold BaseClass* pointers.

std::vector<BaseClass*> vector;

vector.push_back(&a);
vector.push_back(&b);

void DoSetup(BaseClass *obj)
{
    obj->Setup();
}

for_each (vector.begin(), vector.end(), DoSetup);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0
  1. remove = std::vector(); it's not necessary
  2. please move that initialization code A a; B b; std::.... into the main function.
  3. Your for_each is wrong, too.
  4. I don't know what C++ is going to do, if sizeof(BaseClass) is zero.

I think you're hiding too much code: what is GameScreens?

Aitch
  • 1,617
  • 13
  • 24