2

Fairly simple question here, whats the best way to fill a vector outside of a function in a class .cpp file? currently i'm attempting the following which is not working:

std::vector<Player> midfielder(8);

midfielder.at(0) = Midfielder("Default         ",0,"Midfielder");
midfielder.at(1) = Midfielder("David Armitage  ",1,"Midfielder");
midfielder.at(2) = Midfielder("Tom Rockliff    ",2,"Midfielder");
midfielder.at(3) = Midfielder("Gary Ablett     ",3,"Midfielder");
midfielder.at(4) = Midfielder("Dyson Heppel    ",4,"Midfielder");
midfielder.at(5) = Midfielder("Scott Pendlebury",5,"Midfielder");
midfielder.at(6) = Midfielder("Michael Barlow  ",6,"Midfielder");
midfielder.at(7) = Midfielder("Jack Steven     ",7,"Midfielder");

To provide context, 'Midfielder' is a class that inherits from the 'Player' class.

TeamManagment.h

#ifndef TEAMMANAGEMENT_H
#define TEAMMANAGEMENT_H
#include <vector>
#include "Player.h"
#include "Midfielder.h"
#include <string>

class TeamManagement
{
    public:
        TeamManagement();


        void Display_Players();

};

#endif // TEAMMANAGEMENT_H

TeamManagement.cpp

#include <iostream>
#include <string>
#include <vector>
#include "Player.h"
#include "Midfielder.h"
#include "TeamManagement.h"
using namespace std;

TeamManagement::TeamManagement()
{

}

std::vector<Player> midfielder(8);
//errors start occurring on line below: 'midfielder' does not name a type
midfielder.at(0) = Midfielder("Default         ",0,"Midfielder");
midfielder.at(1) = Midfielder("David Armitage  ",1,"Midfielder");
midfielder.at(2) = Midfielder("Tom Rockliff    ",2,"Midfielder");
midfielder.at(3) = Midfielder("Gary Ablett     ",3,"Midfielder");
midfielder.at(4) = Midfielder("Dyson Heppel    ",4,"Midfielder");
midfielder.at(5) = Midfielder("Scott Pendlebury",5,"Midfielder");
midfielder.at(6) = Midfielder("Michael Barlow  ",6,"Midfielder");
midfielder.at(7) = Midfielder("Jack Steven     ",7,"Midfielder");
//errors stop occurring here

void TeamManagement::Display_Players(){

cout<<"Position     Name              ID"<<endl;

for (int i=1;i<8;i++)
    {
         cout<<midfielder[i].Player_Details()<<"   "<<midfielder[i].Get_player_id()<<endl;
    }
}
  • 3
    Note that adding a `Midfielder` into a `vector` would involve [object slicing](http://stackoverflow.com/q/274626/2069064). – Barry May 27 '15 at 11:09
  • "which is not working" You're going to have to be more specific than that. What output did you expect? What did you get? Did the program crash? On which line? Does it not compile? What was the message? Don't make us guess. – eerorika May 27 '15 at 11:19
  • oh sorry, ive only just joined the site. When i compile i get the error 'midfielder' does not name a type – Jackson Frisby-Smith May 27 '15 at 11:21
  • @JacksonFrisby-Smith put the relevant information into your question. And mention which line causes the error. – eerorika May 27 '15 at 11:21
  • error:'midfielder' does not name a type, for each line where i fill a spot in the vector,e.g midfielder.at(0) = Midfielder("Default ",0,"Midfielder"); I get this for each of the 8 occurrences. Ive edited the question and added the .h and .cpp files of the class in question so hopefully that will provide more clarity about my mistakes. Thanks for the help! – Jackson Frisby-Smith May 27 '15 at 11:32
  • Is `std::vector midfielder(8);` really globally in `TeamManagement.cpp`? You also can't have random lines of code like add things to a vector outside a function. You can declare things globally but probably want to avoid this – doctorlove May 27 '15 at 11:39

3 Answers3

3

The first problem is that you cannot perform assignment like that outside of a function. You must use construction or initialization.

With C++98 you cannot populate/initialize a vector outside of a function.

With C++11/14 you can populate one using initializer syntax:

#include <iostream>
#include <vector>

struct Thing {
    int m_i, m_j;
    Thing(int i, int j) : m_i(i), m_j(j) {}
};

std::vector<Thing> things {
    { 1, 2 }, { 2, 3 }
};

int main() {
    std::cout << "things[0].m_j = " << things[0].m_j << '\n';
}

But std::vector won't like you trying to put "Midfielder"s into a vector of Player. Lets use an SSCCE to reconstruct the damage you're doing:

#include <iostream>

struct Base {
    int i;
};

struct Derived : public Base {
    int j;
};

int main() {
    std::cout << "Base size = " << sizeof(Base) << '\n';
    std::cout << "Derived size = " << sizeof(Derived) << '\n';
}

This tells us that Base and Derived have a different size. But you're trying to put these two objects into the same container because they're related. Round peg and square peg are related... They won't fit into the same hole, and this is the problem we have now.

The vector creates space in memory for your elements based on the type you supply, and then it requires you to pass it exactly that type to populate those spaces with, or a type that has a conversion mechanism to the storage type.

If you want to have a container of different types, you'll need to use pointers, but then you're going to run into the problem that what you get back will be a pointer to the base type and you will need to provide yourself with a way to distinguish different player types.

See Store derived class objects in base class variables for the C++98 approach. In modern C++ (11 and 14) you should use smart pointers, e.g.

std::vector<std::unique_ptr<Base>>

std::vector<std::shared_ptr<Base>>
Community
  • 1
  • 1
kfsone
  • 23,617
  • 2
  • 42
  • 74
  • I think i may change the vector to be 'Midfielder's instead of 'Player's and create separate vectors for each position. And how would i go about initializing the vector so that i can use its elements in functions throughout the class? – Jackson Frisby-Smith May 27 '15 at 13:54
2

Presumably default constructing a Midfielder doesn't make a lot of sense, so you can reserve the memory, then emplace_back into the vector.

std::vector<Player> midfielder {};
midfielder.reserve(8);

midfielder.emplace_back("Default         ",0,"Midfielder");
midfielder.emplace_back("David Armitage  ",1,"Midfielder");
midfielder.emplace_back("Tom Rockliff    ",2,"Midfielder");
midfielder.emplace_back("Gary Ablett     ",3,"Midfielder");
midfielder.emplace_back("Dyson Heppel    ",4,"Midfielder");
midfielder.emplace_back("Scott Pendlebury",5,"Midfielder");
midfielder.emplace_back("Michael Barlow  ",6,"Midfielder");
midfielder.emplace_back("Jack Steven     ",7,"Midfielder");
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
2

midfielder.at(0) = Midfielder("Default ",0,"Midfielder"); is a statement. You've put that and similar statements in (global) namespace scope. That's your bug. Only declarations may be in namespace scope. You must put your statements inside a function.

The error message stems from the fact that declarations which don't start with a keyword start with a type name. Since midfielder is not a keyword, the compiler expects it to be a type name but it isn't one, so you get the error.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • It's more of a compile error than a bug - the bug will happen with the object slicing as mentioned in the comments. – doctorlove May 27 '15 at 11:55
  • @doctorlove i'd consider it as a syntax bug. There are wide variety of definitions for bugs. And yeah, it's not the only bug in the code. – eerorika May 27 '15 at 12:51