Home > Back-end >  How to create pair with class (C )
How to create pair with class (C )

Time:12-24

I am trying to create a map that contains pairs of different classes. But for some reason I cannot get it done.
do someone know what is wrong with my code.
This is where the error occured

#pragma once
#include <iostream>
#include "Piece.h"
#include <map>
#include "Knight.h"

std::map<char, Piece> pieces_types;

class Piece;

class Board
{
public:
    Board();
    ~Board();

private:
    void init_map()
    {
        pieces_types.insert(std::pair<char, Piece>('K', Knight));
    }
};

The Piece class is an pure abstract class and Knight is the successor of Piece. This is how Knight.h look like

#pragma once
#include <iostream>
#include "Piece.h"

class Knight : public Piece
{

};

And this is the error that I get

'Knight': illegal use of this type as an expression

CodePudding user response:

'Knight': illegal use of this type as an expression you can use type names as an actual value in other languages but not c .

To make a lookup table from piece character to some action on that piece such as getting its name or instantiating an instance, the easiest way would be a switch statement (since there are only 6 peices it wouldnt be too cumbersome):

#include <memory>

std::unique_ptr<Piece> make_piece(char c) {
    switch (c) {
        case 'K': return std::make_unique<Knight>();
        // etc...
    }
}

Another option is an std::map of chars to instances of a factory class or some template programming but for someone new to c that seems overkill especially when there are only 6 piece types and know there will never be more or less types.

CodePudding user response:

Storing polymorphism data in c is far different from that in other languages

Java:

public class Board {

    private static Map<Character, Piece> pieceTypes = new HashMap<>();

    private void initMap() {
        pieceTypes.put('K', new Knight());
    }
}

You can directly store a Knight inside a Piece because in java it is stored as a reference

C code that does the same thing:

std::map<char, std::unique_ptr<Piece>> pieces_types;

class Board
{
private:
    void init_map()
    {
        pieces_types.insert(std::pair<char, std::unique_ptr<Piece>>('K', new Knight()));
    }
};

You can see that what I store in the map are std::unique_ptr<Piece>s, not Pieces

Here a std::unique_ptr<> is a pointer, which is similar to that reference in java. By storing pointers you can put data of different types inside one container

Though this isn't the only way to do that.


So why is storing data of derived classes in a container of base class not allowed in c ? You can think in this way:

Objects with automatic storage duration is allocated and initialized on the stack, like

Piece p1;

It's size must be known, and fixated. In c the runtime stack size of a function is calculated compile-time. When you call a function, it always allocate stack memory at first.

So assigning a derived object to it is ill-formed:

Knight p2;
p1 = p2; // ill-formed

Because the size of Knight may be larger than Piece, there may be no available space for p1 to store a Knight

But if p1 is a pointer, and objects are with dynamic storage duration, it becomes possible:

std::unique_ptr<Piece> p1{ new Piece() }; // { new Piece } is also OK
p1 = new Knight(); // OK

Here the two objects are dynamicly allocated on the heap, they does not occupy stack memory

So back to your example, storing Knight into pair<char, Piece>'s second slot is ill-formed because pair is just a wrapper of two values with automatic storage duration

  •  Tags:  
  • c
  • Related