Reputation: 157
I'm new to C++ and I'm having trouble with this. So I'm trying to make classes that can call on each other's fields using a generic subclass.
Basically, I'm trying to make a game where there is a generic type and three types that have strengths/weaknesses against each other. I only really have experience in Java, and the translation to c++ for this kind of thing isn't clicking for me
Generic type splits into three types: type 1, type 2, type 3.
Generic type needs to be concrete
In the generic type there are fields attack, defense, hitpoints
types 1, 2, and 3 all inherit these fields.
I'm trying to make a virtual function in the generic class:
virtual void attack(Generic* g);
Problem is, when I try to make type_1.attack(generic)
for example, I want to do g->hitpoints to get generic's hitpoints, but it just doesn't seem to work like that in C++.
Additionally, I know I must be doing something wrong, because type 1, 2 and 3 all include the generic type's header, but if I want to include those 3 headers in main.cpp, it'll give me an error for declaring generic 3 separate times.
How would I go about doing this?
Sorry this is a very specific question and it's a little bit vague. Please let me know if I need to clarify anything
Edit: Here is the basic setup of what I'm talking about
//in generic.h
class Generic {
protected:
int hitpoints;
int strength;
int defense;
public:
virtual void attack(Generic* g);
};
//type1.h
#include 'generic.h'
class Type1 : public Generic {
void attack (Generic* g);
};
//in type1.cpp
void Type1::attack(Generic*g) {
g->hitpoints = strength - g->defense;
}
Upvotes: 1
Views: 1151
Reputation: 11
The meaning of protected
for data members is subtly different from what you might expect. When you have a class A
with a protected data member d
and a class B
that inherits from A
(with public inheritance), then B
's member functions can access d
– but only on objects of type B
, not on any object of type A
. If that seems confusing, a code example will hopefully make it clearer:
class A {
protected:
int d;
};
class B : public A {
void fine(B& b) { b.d = 0; }
void wrong(A& a) { a.d = 0; }
};
int main() { }
As the names indicate, the assignment in functions fine
is ok, but you'll get a compiler error for the one in wrong
if you try to compile the code. The best way to deal with this is probably to make the data members private and write protected member functions that operate on them, as in abyss.7's answer.
For the double inclusion problem, use either include guards or #pragma once.
Upvotes: 1
Reputation: 11028
To avoid your second problem (a class defined multiple times), there is something called include guards (they guard you from including the same file several times). It works like this way:
// File: type1.h
// At the very beginning
#ifndef type1_h
#define type1_h
// Here come the rest of your file and, at the end:
#endif
This way, the contents of the file are only included once, because after that type1_h
will be defined, so everything will be skipped. This may be the only use of #define
that is universally accepted in C++.
As for your first problem, protected
means that derived classes can read that member for themselves or objects of their own class, but nobody else. This includes that derived classes cannot read that member for objects belonging to another class, including the base class itself. I'm afraid you'll have to rethink your design.
The best that you can do is just changing the privacy of the protected
members or, even better, provide public
accessors and keep the data members private
. public
data members are seldom a good idea in classes (structs are a different thing):
class Generic {
private:
int hitpoints;
int strength;
int defense;
public:
virtual void attack(Generic* g);
void SetHitpoints(int hp) {hitpoints = hp;}
int GetDefense() {return defense;}
};
Upvotes: 1
Reputation: 14462
You should do something like this:
// generic.h
#pragma once
class Generic {
protected:
int hitpoints_;
int strength_;
int defense_;
void do_damage(Generic* g, int damage) { g->hitpoints_ -= damage; }
public:
virtual void attack(Generic* g) = 0;
int hitpoints() const { return hitpoints_; }
int strength() const { return strength_; }
int defense() const { return defense_; }
};
// type1.cpp
void Type1::attack(Generic* g) {
do_damage(g, strength_ - g->defense());
}
Upvotes: 1
Reputation: 596256
An object can access its own protected
members that are inherited from a base class. But an object cannot access another object's protected
members. That is the difference between private
vs protected
- private
members can only be accessed by the class that declares them, but protected
members can be accessed by the declaring class and its descendants. Both are still private to outside code, though.
To do what you are attempting, hitpoints
needs to be public
.
Upvotes: 3
Reputation: 13588
type 1, 2 and 3 all include the generic type's header, but if I want to include those 3 headers in main.cpp, it'll give me an error for declaring generic 3 separate times.'
You need to make sure that the class is declared only once. This is usually done with guards in the .h file:
//generic.h
#ifndef GENERIC_H
#define GENERIC_H
//all declarations go here
#endif /* GENERIC_H */
When you type #include "generic.h"
, the C++ processor will basically just paste the contents of foo.h. Since you included it thrice (via the includes for classes Type1, Type2 and Type3, that each include generic.h), the class is delcared three times.
Upvotes: 1