-2

I am attempting to call a virtual function of a class object. The object is in a 2d vector and I am sure it exists because it prints out the 'symbol,' that I have assigned to it. I have an abstract base class that my other classes derive from. Whenever I attempt to call this function though, it gives me a seg fault.

// In my Cave class constructor, I create my 2d array, and make all the elements default constructors of a room which is an 'Empty,' room.
Room r;
                grid = vector<vector<Room> > (width, vector<Room>(width));
                for(int i = 0; i < width; i ++){
                        for(int j = 0; j < width; j++){
                                Room r;
                                grid[i][j] = r;
                        }
                }
//Here is where I set up all of my 'special,' Rooms
Room g('G');
                        Room b('B');
                        Room b2('B');
                        Room p1('P');
                        Room p2('P');
                        Room w('W');

                        this->grid[0][0] = g;
                        this->grid[0][1] = b;
                        this->grid[0][2] = b2;
                        this->grid[0][3] = p1;
                        this->grid[0][4] = p2;
                        this->grid[0][5] = w;
// This is my room class .cpp I have a non default constructor that should make a new Event object of one of the other object
#include <iostream>
#include <vector>
#include <cstdlib>
#include "room.h"
#include "event.h"
#include "gold.h"
#include "wumpus.h"
#include "pit.h"
#include "empty.h"
#include "bats.h"

using namespace std;

        Room::Room(){
                cout << "making room" << endl;
                symbol = ' ';
                Event *e = new Empty;
        }
        Room::Room(char c){
                cout << "Non-defualt" << endl;
                if(c == 'G'){
                        Event *e = new Gold;
                        symbol = 'G';
                }
                else if(c == 'W'){
                        Event *e = new Wumpus;
                        symbol = 'W';
                }
                else if(c == 'P'){
                        Event *e = new Pit;
                        symbol = 'P';
                }
                else if(c == 'B'){
                        Event *e = new Bats;
                        symbol = 'B';
                }

        }
        void Room::sense(){
                cout << this->symbol << endl;
                this->e->percept();
        }
        char Room::get_symbol(){
                return(this->symbol);
        }
// my Room header file
#ifndef ROOM_H
#define ROOM_H

#include <iostream>
#include "event.h"
#include "bats.h"
#include "empty.h"
#include "wumpus.h"
#include "gold.h"
#include "pit.h"

using namespace std;

class Room {
        public:
                Event *e;
                char symbol;
                Room();
                Room(char);
                void sense();
};
#endif
//here is where I call my 'Sense()' function that is apart of my room class
void Cave::nearby(){
                int x = p.spot/width;
                this->grid[(x - 1)][p.spot % width].sense();
                this->grid[(x + 1)][p.spot % width].sense();
                this->grid[x][(p.spot % width) + 1].sense();
                this->grid[x][(p.spot % width) - 1].sense();
        }
// my abstract event header file
#ifndef EVENT_H
#define EVENT_H
#include <iostream>
using namespace std;
class Event {
        public:
                Event();
                virtual void percept() = 0;
                virtual void encounter() = 0;
};
#endif
//my abstract event.cpp
#include <iostream>
#include "event.h"

using namespace std;

        Event::Event(){
                cout << "making event" << endl;
        }
//Finally my header of the different room types, this one is gold. but they are all the exact same outline and stuff
#ifndef GOLD_H
#define GOLD_H

#include <iostream>
#include <string>
#include "event.h"

using namespace std;

class Gold : public Event {
        private:
                string name;
        public:
                Gold();
                void percept();
                void encounter();
};
#endif
//here is my gold.cpp
#include <iostream>
#include <string>
#include "gold.h"
#include "event.h"

using namespace std;

        Gold::Gold(){
                name = "gold";
                cout << "making gold" << endl;
        }
        void Gold::percept(){
                cout << "You see a glimmer nearby..." << endl;
        }
        void Gold::encounter(){
                cout << "encounter" << endl;
        }

It should print out "you see a glimmer nearby." or any of the other messages, but instead I get a seg fault.

  • 1
    Not related to your problem, but the loop in your first snippet is redundant ; the vector objects are already constructed using their default constructor – M.M May 24 '19 at 00:08
  • That's a ton of code. Do some debug first, find out more precisely what is happenning and share it here. – goodvibration May 24 '19 at 00:09
  • 1
    Work on a [mcve] because that's just too much code and it's incomplete. Narrowing down the problem often leads to finding a solution on your own. – Retired Ninja May 24 '19 at 00:12
  • And BTW, in the 3rd block of code (`Room` constructor), you are NOT initializing the **member variable** `e`, but just declaring a **local variable** (which happens to be of the same name). – goodvibration May 24 '19 at 00:12
  • @goodvibration I agree it is a lot of code, I just honestly have no clue where the problem lies, so I thought I might need to post more code than usual. – Matthew Jacobsen May 24 '19 at 00:12
  • Unrelated: You may find `std::unique_ptr` and `std::make_unique` helpful in managing the book-keeping. – user4581301 May 24 '19 at 00:27

1 Answers1

1
            if(c == 'G'){
                    Event *e = new Gold;
                    symbol = 'G';
            }

This creates a brand new Event *, also called e and sets it to point to a new Gold. That's not what you want. You want to set the existing member named e to point to the new Gold. So you want:

            if(c == 'G'){
                    delete e; // don't leak the existing object
                    e = new Gold;
                    symbol = 'G';
            }

You have the same issue everywhere else, including here:

            Event *e = new Empty;

Which should be:

            e = new Empty;

If your compiler didn't give you a warning about creating a new variable that shadows an existing class member, get a better compiler or learn how to turn up its warnings and be sure to pay attention to them.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278