정민섭
정민섭

Reputation: 21

How to access vector in map

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <cstdlib>
#include <ctime>

using namespace std;
class ship
{
    protected:
    string type;
    int size;
    int hits;
};
int main()
{
    map< char,vector<ship*> > board;
    for(int i=0;i<10;i++)
    {
        vector<ship*> v;
        for(int j = 0;j<10;j++)

        {
            ship *s = new ship();
            v.push_back(s);
        }
        board['A'+i] = v;
    }//set board 
}

I made map<char,vector<ship*> > board. How can I access to type (in ship class) from first ship pointer in first element of vector in map?

Upvotes: 0

Views: 1529

Answers (3)

vianney
vianney

Reputation: 161

Ok, maybe my answer will be a bit over the top, and it's not really what you ask, I know, but it could help you understand why values in ship are protected, and I have too much time it seems.

Since it's a very common problem to build a game around ships/monsters/objects that have a common base of methods and attributes, there is a very common way to implement this. It's based on a three level inheritance.

1. Interface

It will define what methods can be called from the outside, it's a contract. Every class that inherits from it MUST implement those methods.

In your case a basic one would look like this:

class IShip
{
    public:
        virtual ~IShip() // needs this, see link below
        { std::cout << "Interface destructor called" << std::endl; }

        virtual std::string type() = 0;
        virtual int         size() = 0;
        virtual int         hits() = 0;

        virtual void    specialMove() = 0;
};

Reason for the virtual dtor.

2. Abstract

It inherits from this interface, and implement the basic methods that are re-usable by every ship, it could be done this way:

class AShip : public IShip
{
    public:
        AShip(std::string type, int size, int hits)
            : _type(type)
            , _size(size)
            , _hits(hits)
        { std::cout << "Abstract constructor called" << std::endl; }

        virtual ~AShip() // still needs this
        { std::cout << "Abstract destructor called" << std::endl; }

        virtual inline std::string type()   // inline keyword to put the code in-place instead of calling it
        { return _type; }                   // should only do this on very small methods

        virtual inline int size()           // virtual are not necessary
        { return _size; }                   // but it's best practice to clarify code

        virtual inline int hits()
        { return _hits; }

        // -- need overload method
        virtual void    specialMove() = 0;

    // -- protected since it needs to be accessible from child classes
    protected:
        std::string _type;
        int         _size;
        int         _hits;
};

At this point you can not instantiate anything because both those classes are virtual. More about virtual classes

An interface being a pure virtual class (because every methods defined have '= 0').

3. Instanciable

What you can do now is implement easily multiple classes that inherits from AShip but still specify something special, you are right, i'm talking about the specialMove, i'll create two classes for the sake of my example:

class TheDestructor : public AShip
{
    public:
        TheDestructor()
            : AShip("The Destructor", 20, 100)
            , _attack("DestructionOver9000")
        { std::cout << "TheDestructor constructor called" << std::endl; }

        virtual ~TheDestructor() // still needs this to help the compiler
        { std::cout << "TheDestructor destructor called" << std::endl; }

        inline void specialMove() // specialMove overload
        { std::cout << "Attack " << _attack << " from " << _type << std::endl; }

    private:
        std::string _attack;
};

class MyPunyShip : public AShip
{
    public:
        MyPunyShip()
            : AShip("My Puny Ship", 1, 1)
            , _escape("just fly away as fast as he can...")
        { std::cout << "MyPunyShip constructor called" << std::endl; }

        virtual ~MyPunyShip() // still needs this to help the compiler
        { std::cout << "MyPunyShip destructor called" << std::endl; }

        inline void specialMove() // specialMove overload
        { std::cout << _type << " " << _escape << std::endl; }

    private:
        std::string _escape;
};

Now let us test what has been done:

int     main()
{
    std::map<std::string, IShip*>   ships;

    ships.insert(std::make_pair("The Destructor", new TheDestructor));
    std::cout << std::endl;
    ships.insert(std::make_pair("My Puny Ship", new MyPunyShip));
    std::cout << std::endl;

    for (std::map<std::string, IShip*>::iterator itS = ships.begin() ; itS != ships.end() ; ++itS)
    {
        // *itS to access the data of the iterator
        // second to access the second member of the pair
        std::cout << "type: " << (*itS).second->type() << "\n";
        std::cout << "size: " << (*itS).second->size() << "\n";
        std::cout << "hits: " << (*itS).second->hits() << "\n";
        std::cout << std::endl;
    }

    ships["The Destructor"]->specialMove();
    ships["My Puny Ship"]->specialMove();
}

You can only call the methods that are in the interface, because the type in the map is an IShip, but it allows you to implement various ships with different stats.

let's see that output...

Output:

Abstract constructor called
TheDestructor constructor called

Abstract constructor called
MyPunyShip constructor called

type: My Puny Ship - size: 1 - hits: 1

type: The Destructor - size: 20 - hits: 100

Attack DestructionOver9000 from The Destructor
My Puny Ship just fly away as fast as he can...

But, but... Something is missing right? Something seems very odd... What??? I forgot to use delete??

Well, I forgot to use c++11 as a whole to make the example a bit smaller and to keep what I was trying to convey clear. What I should have used here is std::unique_ptr or std::shared_ptr.

The 'new' main would look like this and compile with c++11 flag enabled:

int     main()
{
    std::map<std::string, std::shared_ptr<IShip>>   ships;

    ships.emplace(std::make_pair("The Destructor", std::shared_ptr<IShip>(new TheDestructor)));
    ships.emplace(std::make_pair("My Puny Ship", std::shared_ptr<IShip>(new MyPunyShip)));

    for (auto ship : ships) // damn that's neat...
    {
        std::cout << "type: " << ship.second->type() << " - ";
        std::cout << "size: " << ship.second->size() << " - ";
        std::cout << "hits: " << ship.second->hits() << "\n";
    }

    ships["The Destructor"]->specialMove();
    ships["My Puny Ship"]->specialMove();
}

Output:

Abstract constructor called
TheDestructor constructor called

Abstract constructor called
MyPunyShip constructor called

type: My Puny Ship - size: 1 - hits: 1
type: The Destructor - size: 20 - hits: 100

Attack DestructionOver9000 from The Destructor

My Puny Ship just fly away as fast as he can...

TheDestructor destructor called
Abstract destructor called
Interface destructor called
MyPunyShip destructor called
Abstract destructor called
Interface destructor called

Wow, I missed you so much c++11. Joke apart, you can see that the destructors are automatically called for our IShip* pointers, pretty nice if you ask me.

Why both Interface and Abstract, seems like overdoing it? My take on this is that one could need a IVehicle but create AShip, ACar, ASpaceCraft etc... with different limitations. But it's a very valid question, and you should adapt this "pattern" to fit your needs and your philosophy.

Hope it can help you understand a few concepts on c++/c++11 and inheritance, next step for you is to build a factory ;)

Upvotes: 1

user5058091
user5058091

Reputation:

First, you should declare type as public.

Then, you should do board[index].front()->type

Important: the index should be a char variable, since the type of the key of the map board is char.

example:

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <cstdlib>
#include <ctime>

using namespace std;
class ship
{
    public:
    string type;
    int size;
    int hits;
};
int main()
{
    map< char, vector<ship*> > board;
    for (int i = 0; i<10; i++)
    {
        vector<ship*> v;
        for (int j = 0; j<10; j++)
        {
            ship *s = new ship();
            s->type = "Cannon ship";
            v.push_back(s);
        }
        board['A' + i] = v;
    }//set board 
    cout << board['A'].front()->type << endl;
}

Upvotes: 0

polfosol ఠ_ఠ
polfosol ఠ_ఠ

Reputation: 1898

Since type is declared as protected, you can't normally access that. protected members are only accessible by friend classes or those who inherit from the class. The easiest solution is to declare the variables as public. But it has its own caveats.

Upvotes: 0

Related Questions