base class undefined

Pages: 12
I'm try to use inheritance here where the "started" class is the parent and as I made the "BeginJourney" the child things haven't been working. It says that the "started" base class is undefined.

Game.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
 #include<iostream>
#include<vector>
#include "BeginJourney.h"
using namespace std;

class started
{
public:
	void startingclass();
	void getclass();
protected:
	int starting_class, intelligence, strength, agility;
	string attributes[3] = { "intelligence","strength","agility" };
	vector<int> attribute_points;
private:
	char redo;
};

void started::startingclass()
{
	cout << "Pick a class to choose from: " << endl;
	cout << "-------------------------------" << endl;
	cout << "1. Mage / 2. Ninja / 3.Barbarian" << endl;
	cout << "-------------------------------" << endl;
	try {
		cin >> starting_class;
		if (starting_class > 3)
		{
			throw starting_class;
		}
	}
	catch (int starting_class)
	{
		cout << "Can only choose the three classes presented" << endl;
		cout << "Do you wish to retry?(Y/N): ";
		cin >> redo;
		if (toupper(redo) == 'Y')
			startingclass();
		else
			exit(1);
	}
}

void started::getclass()
{
	switch (starting_class)
	{
	case 1:
		cout << "Class chosen: Mage" << endl;
		attribute_points = vector<int>{ intelligence=6,strength=2,agility=3 };//vector used to dynamically set stats based on class
		
		for (int i = 0; i < 3; i++)
		{
			cout << attributes[i] << ": " << attribute_points[i]<< endl;
		}
		break;
	case 2:
		cout << "Class chosen: Ninja" << endl;
		 attribute_points = vector<int>{ intelligence=4,strength=4,agility=6 };
		for (int i = 0; i < 3; i++)
		{
			cout << attributes[i] << ": " << attribute_points[i] << endl;
		}
		break;
	case 3:
		cout << "Class chosen: Barbarian" << endl;
		 attribute_points = vector<int>{ intelligence=2,strength=7,agility=3 };
		for (int i = 0; i < 3; i++)
		{
			cout << attributes[i] << ": " << attribute_points[i] << endl;
		}
		break;
	}
}

int main()
{
	int BreakOut = 0;
	started classes;
	BeginJourney LetsGo;
	classes.startingclass();
	classes.getclass();
	cout << endl;
	LetsGo.Cell(BreakOut);
}


BeginJourney.h
1
2
3
4
5
6
7
8
9
10
11
#pragma once
class BeginJourney :public started
{
public:
	//BeginJourney();
	void Cell(int BreakOut);

private:
	
	
};


BeginJourney.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include <iomanip>
#include "BeginJourney.h"
using namespace std;

void BeginJourney::Cell(int BreakOut)
{

	cout << "You wake up in a cell with a dilapitated wall behind you, a window one may sqeeze threw above" << endl; 
	cout<< "and a sleeping guard outside the cell." << endl;
	cout << endl;
	cout <<  setfill('-') <<setw(65) << "What will you do?"<<setw(55)<<"-"<<setfill('-') << endl;
	cout << "1. Crush the ruined wall behind you / 2.Jump and climb to reach the window / 3.Hypnotise the guard"<< endl;
	cin >> BreakOut;
	
}
You will probably need to move your started class declaration into a header file that can be #included into your BeginJourney.h header file.



Okay so I added a header file for started (called Start now) and a separate cpp for it. I also put #include "Start.h" into the BeginJourney header file.

Start.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#pragma once
#include <vector>
class Start
{
public:
	void startingclass();
	void getclass();
protected:
	int starting_class, intelligence, strength, agility;
	string attributes[3] = { "intelligence","strength","agility" };
	vector<int> attribute_points;
private:
	char redo;
};


Start.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<iostream>
#include <vector>
#include "Start.h"
using namespace std;

void Start::startingclass()
{
	cout << "Pick a class to choose from: " << endl;
	cout << "-------------------------------" << endl;
	cout << "1. Mage / 2. Ninja / 3.Barbarian" << endl;
	cout << "-------------------------------" << endl;
	try {
		cin >> starting_class;
		if (starting_class > 3)
		{
			throw starting_class;
		}
	}
	catch (int starting_class)
	{
		cout << "Can only choose the three classes presented" << endl;
		cout << "Do you wish to retry?(Y/N): ";
		cin >> redo;
		if (toupper(redo) == 'Y')
			startingclass();
		else
			exit(1);
	}
}

void Start::getclass()
{
	switch (starting_class)
	{
	case 1:
		cout << "Class chosen: Mage" << endl;
		attribute_points = vector<int>{ intelligence = 6,strength = 2,agility = 3 };//vector used to dynamically set stats based on class

		for (int i = 0; i < 3; i++)
		{
			cout << attributes[i] << ": " << attribute_points[i] << endl;
		}
		break;
	case 2:
		cout << "Class chosen: Ninja" << endl;
		attribute_points = vector<int>{ intelligence = 4,strength = 4,agility = 6 };
		for (int i = 0; i < 3; i++)
		{
			cout << attributes[i] << ": " << attribute_points[i] << endl;
		}
		break;
	case 3:
		cout << "Class chosen: Barbarian" << endl;
		attribute_points = vector<int>{ intelligence = 2,strength = 7,agility = 3 };
		for (int i = 0; i < 3; i++)
		{
			cout << attributes[i] << ": " << attribute_points[i] << endl;
		}
		break;
	}
}


for some reason I'm getting a lot of errors now from both of these such as "attributes: unknown override specifier"
Last edited on
Please post the error messages exactly as they appear in your development environment. These messages have important information embedded within them to aid in locating and fixing the issues.

By the way in your Start.h header file you will need to properly scope the classes from the std namespace. You also need to specify all the proper #includes for the standard classes you are trying to use.




For the start.h file it has the following for line 10:

'attributes': unknown override specifier
syntax error : missing ',' before '['
unexpected tokens preceding '{'
syntax error:')'

For line 11:
syntax error:missing ';' before '<'
missing type specifier - int assumed
unexpected tokens preceding ';'

For line 38 on Start.cpp:
'attribute_point': undeclared identifier

line 42
'attributes':undeclared identifier
'attribute_points':undeclared identifier

line 50
'attributes':undeclared identifier
'attribute_points':undeclared identifier

line 55
'attribute_points':undeclared identifier

line 58
'attributes':undeclared identifier
'attribute_points':undeclared identifier

There are more, but hopefully this creates a picture. Some of the errors say the same thing for different lines. This whole thing is messy.
Make sure to use these:
std::vector
std::string
in your start.h header (you have to specify where those objects are coming from)

Try including Start.h in your game.cpp file
Last edited on
@OP

You might consider a re-think of this project. Keep what you have but re-shuffle/re-organize it before you go too far descending into a very complicated structure.

1. Your classes are simpler if they are separate from the interface. Menus within classes are not a good idea - detract from what the class is really about, suit only 1 platform, add complications and make editing difficult.

2. It appears you have a Game class and 3 Players - Maje, Ninja and Barbarian - inheriting their unique properties from the Player class.

3. The (separate) menu drives the Game.

4. There are numerous Factory patterns that do the job of the getClass() function that deliberately separate the Players from the Factory.
eg https://www.geeksforgeeks.org/design-patterns-set-2-factory-method/

Okay I decided to start from scratch because going through all the code was maddening. I''ll try my best with the factory patterns.

That being said while slowly remaking this I think I found one of the problems from my previous attempt. It all comes from the "Start" header file line 10.

here's what the errors say:
'stats':unknown override specifier
syntax error: missing ',' before '['
unexpected token(s) preceding '{'; skipping apparent body function
syntax error: missing ')' before ';'
syntax error:')'
unexpected token(s) preceding ';'

Here's the code:
source.cpp
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include "Start.h"
using namespace std;

int main()
{
	int choice = NULL;
	Start start;
	start.starting_class(choice);
}


Start.h
1
2
3
4
5
6
7
8
9
10
11
#pragma once
using namespace std;
enum {Ninja,Mage,Barbarian};
class Start
{
public:
	void starting_class(int choice);

protected:
	string stats[3] = { "algility","stregnth","intelegence" };
};


Start.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "Start.h"
#include <iostream>
void Start::starting_class(int choice)
{
	std::cout << "Picking a class: 1.Ninja 2.Mage 3.Barbarian" << std::endl;
	std::cin >> choice;
	switch (choice)
	{
	case 1:
		std::cout << "Ninja";
		break;
	case 2:
		std::cout << "Mage";
		
	}
		

}

Note that with Start.cpp I'm obviously still working on it.
You need to include <string> in your Start class, preferably in the header.

Another suggestion is to include all custom headers AFTER C++ library headers, as you did in your source.cpp file.

Recommended, DO NOT put using namespace std; in a header file, put it in your source file(s).

REALLY recommended, don't use it, period.

https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice
First it is a very bad practice to use the "using" statements in the global scope of a header. You should properly scope the standard classes using the scope resolution operator:: (std::string, std::vector).

Second you need to include all the required header files. You need to #include the headers in all files that try to use the items.

Third your compiler error messages should be telling you exactly where it detects the problems, you left out that important information from your snippet error reports.

@Deadweight77

I've refactored the geeks factory and this might give you a better picture of what I'm driving at.
1. Your naming of classes could be more self-explanatory.
2. A Game class comes later where the setup occurs.
3. Note that the Players only return strings etc - ie you can use a Player class on any platform, not just the console
4. Obviously each of the Player classes need to be update/modified to incorporate their properties and methods as required - including inheritance where appropriate.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <iostream>
#include <string>

using namespace std;

enum PlayerType
{
    PL_Maje, PL_Ninja, PL_Barbarian
};

// Library classes
class Player
{
public:
    virtual string printPlayer() = 0;
    static Player* Create(PlayerType type);
};

class Maje : public Player
{
public:
    string printPlayer()
    {
        return "Maje";
    }
};

class Ninja : public Player
{
public:
    string printPlayer()
    {
        return "Ninja";
    }
};

class Barbarian : public Player
{
public:
    string printPlayer()
    {
        return "Barbarian";
    }
};

// Factory method to create objects of different types.
// Change is required only in this function to create a new object type
Player* Player::Create(PlayerType type)
{
    if (type == PL_Maje)
        return new Maje;
    else if (type == PL_Ninja)
        return new Ninja;
    else if (type == PL_Barbarian)
        return new Barbarian;
    else return NULL;
}

// Client class
class Client
{
public:
    
    // Client doesn't explicitly create objects
    // but passes type to factory method "Create()"
    Client()
    {
        PlayerType type = PL_Ninja;
        pPlayer = Player::Create(type);
    }
    ~Client()
    {
        if (pPlayer)
        {
            delete[] pPlayer;
            pPlayer = NULL;
        }
    }
    Player* getPlayer()
    {
        return pPlayer;
    }
    
private:
    Player *pPlayer;
};


// Driver program
int main()
{
    Client *pClient = new Client();
    Player * pPlayer = pClient->getPlayer();
    cout << "I am a " << pPlayer->printPlayer() << '\n';
    
    Player *pBarb = Player::Create(PL_Barbarian);
    cout << pBarb->printPlayer() << " just created ...\n";
    
    return 0;
}


PS using std and all that might be eventually relevant but don't sweat it :)
Last edited on
Not sure if this thread is dead or not, but for the factory pattern I was able to create it and learn it. However, for the pattern is there a way it can print out the starting class you chose instead of being always one class from line 68? I tried a switch function, but didn't work.

Here's what I added, but didn't work:

1
2
3
4
5
void Client::display()
{
	std::cout << "choose a class: 1.mage 2. ninja 3.barbarian" << std::endl;
	std::cin >> choice;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
Client()
	{
		display();
		switch (choice)
		{
		case 1:player_type type = mage;
			break;
		case 2:player_type type = ninja;
			break;
		case 3:player_type type = ninja;
			break;
			Pplayer = player::create(type);
		}		
	}

I know why now why it doesn't work, but just asking if there's another method. If statements didn't work either if you were wondering.
Last edited on
You're mixing interface issues with the object classes which is not good practice. (for interface stuff use a Menu class perhaps)

display() doesn't return anything so you need to look carefully at the scope of 'choice' within Client() - tricky to resolve

Client doesn't create Player objects, Player::Create(type) does. You won't get arrested by going outside the Factory pattern but there is a deliberate discipline to it.

Use a switch instead of if/else cascade but use it properly - you need a default case for starters.

I'd put line 12 outside the switch block.

case numbers are OK, the enum is better for self-documentation purposes :)

Once I go and make a separate class dedicated to interface, should I use friend function to access the choice variable from the Client class like this?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Client
{
public:
	Client()
	{
		player_type type = mage;
		Pplayer = player::create(type);
	}
	~Client()
	{
		if (Pplayer)
		{
			delete[] Pplayer;
			Pplayer = NULL;
		}
	}
	player* getclass() { return Pplayer; }
private:
	int choice;
	friend int Menu::menu(Client &fist);
	player* Pplayer;
};

class Menu
{
public:
	int menu(Client& fist)
	{
		std::cout << "choose a class: 1.mage 2. ninja 3.barbarian" << std::endl;
		std::cin >> fist.choice;// for some reason cannot access 'choice' from line 65
	}

private:

};

Also I'm just using "fist" as a place holder for now since I cannot think of any meaningful name atm.
Last edited on
No need to have complicated friend stuff. All you're doing is creating a menu to do exactly the same as main() and that can be done with a function/method in the Menu class to process the chosen option along with the obvious Menu::display() method ...
Ok, so I changed somethings a little, but can't figure out how to change character class based on what number you enter. The switch function I have doesn't work because of the redefinition of 'type'. Also it says that 'type' is skipped by by 'case' label and 'default' label as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <iostream>
#include <string>


//factor pattern is used to make the code more decoupled   
enum player_type{mage,ninja,barbarian};

//Library classes
class player
{
public:
	virtual std::string printPlayer() = 0;
	static player* create(player_type type);
};

class Mage :public player
{
public:
	std::string printPlayer() { return "Mage"; }
};

class Ninja :public player
{
public:
	std::string printPlayer() { return "Ninja"; }
};

class Barbarian :public player
{
public:
	std::string printPlayer() { return "Barbarian"; }
};

//Factory method 
player* player::create(player_type type)
{
	if (type == mage)
		return new Mage();
	else if (type == ninja)
		return new Ninja();
	else if (type == barbarian)
		return new Barbarian();
	else return NULL;
}

//client class
class Client
{
public:
	Client()
	{
		std::cin >> choice;
		switch (choice)
		{
		case 1: player_type type = mage;
			break;
		case 2:player_type type = ninja;
			break;
		case 3:player_type type = barbarian;
			break;
		default:exit(1);
		Pplayer = player::create(type);
		}
		
		
	}
	~Client()
	{
		if (Pplayer)
		{
			delete[] Pplayer;
			Pplayer = NULL;
		}
	}
	player* getclass() { return Pplayer; }
private:
	int choice;
	player* Pplayer;
};

class Menu
{
public:
	Menu(){ std::cout << "choose a class: 1.mage 2. ninja 3.barbarian" << std::endl; }
};

int main()
{
	Menu();
	Client *pClient = new Client();//allocating info from the heap 
	player* pPlayer = pClient->getclass();
	std::cout<<pPlayer->printPlayer();
	return 0;
}
Okay do you realize that you're trying to create a new instance of player_type in every case statement?

If you really must create an instance of some type then you will need braces in that case statement to denote a scope. But realize that that scope is only valid within the braces.

You would be better off creating the variable prior to the switch() and just assign a value it that variable in each case.

By the way, do you realize that C++ doesn't require a class for every little thing? For example what is the purpose of placing that cout statement within it's own dedicated class? I haven't looked very closely at the rest of the code but Client code also looks like it may be better off outside of any class.


Forgive me if I 'm coming off stupid here (teaching myself myself how to code sometimes is confusing) but is it something like this your talking about?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Client()
	{
		std::cin >> choice;
		switch (choice)
		{
		case 1: {player_type type = mage;}
			break;
		case 2:{player_type type = ninja;}
			break;
		case 3:{player_type type =  barbarian; }
			break;
		default:exit(1);
		Pplayer = player::create(type);
		}
	}

It currently says 'type' is undefined since putting up the brackets.
This runs with a few small changes however the Client is not the place to have console-oriented cout's and cins. They should be in the relevant (create_a_player) menu. (There could be 50 menu's in the whole game - that's the relevance of a possible Menu class).

I'll leave you to sort out the scope issues

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <iostream>
#include <string>


//factor pattern is used to make the code more decoupled
enum player_type{mage,ninja,barbarian};

//Library classes
class player
{
public:
    virtual std::string printPlayer() = 0;
    static player* create(player_type type);
};

class Mage :public player
{
public:
    std::string printPlayer() { return "Mage"; }
};

class Ninja :public player
{
public:
    std::string printPlayer() { return "Ninja"; }
};

class Barbarian :public player
{
public:
    std::string printPlayer() { return "Barbarian"; }
};

//Factory method
player* player::create(player_type type)
{
    if (type == mage)
        return new Mage();
    else if (type == ninja)
        return new Ninja();
    else if (type == barbarian)
        return new Barbarian();
    else return NULL;
}

//client class
class Client
{
public:
    Client()
    {
        player_type type{ninja};
        
        int choice;
        std::cin >> choice;
        
        switch (choice)
        {
            case 1:
                type = mage;
                break;
            case 2:
                type = ninja;
                break;
            case 3:
                type = barbarian;
                break;
            default:
                break;
        }
        
        Pplayer = player::create(type);
        
        
    }
    ~Client()
    {
        if (Pplayer)
        {
            delete[] Pplayer;
            Pplayer = NULL;
        }
    }
    player* getclass() { return Pplayer; }
private:
    int choice;
    player* Pplayer;
};

class Menu
{
public:
    Menu(){ std::cout << "choose a class: 1.mage 2. ninja 3.barbarian" << std::endl; }
};

int main()
{
    Menu();
    Client *pClient = new Client();//allocating info from the heap
    player* pPlayer = pClient->getclass();
    std::cout<<pPlayer->printPlayer();
    return 0;
}
Thank you! Sorry for the over due reply. I have seen how to use pointers to point to a class member in particular here: https://www.studytonight.com/cpp/pointer-to-members.php

Now thing is, is can only happen when the class member is public, which is bad form, and you said not to stress with friend functions earlier correct? Is there any particular method I should use here to separate the input from the client?
Last edited on
Pages: 12