confused on forward declarations - c++

#pragma once
#include "Player.h"
class Player;
//class SmallHealth;
const int kNumOfCards = 3; //for Player class also
const int kCardLimit = 3;
class Cards
{
private:
protected:
int turnsInEffect;
Player *owner;
public:
Cards()
{turnsInEffect = 1;}
void AssignOwner(Player &player)
{
owner = &player;
}
virtual void PlayCard()
{}
virtual ~Cards(void)
{}
};
class SmallHealth : public Cards
{
public:
void PlayCard()
{
turnsInEffect = 1;
owner->SetHealth(owner->GetHealth() + 5);
//check if health goes over
if(owner->GetHealth() > owner->GetHealthLimit())
{
owner->SetHealth(owner->GetHealthLimit());
}
turnsInEffect--;
}
};
I thought by declaring class Player I wouldn't get these errors:
error C2027: use of undefined type 'Player
see declaration of 'Player'
error C2227: left of '->SetHealth' must point to ...
Checking on error 2027, seems I have to explicitly have the whole class before the Cards class, but I thought the forward class declaration would make it unnecessary. How I have it set up is that Cards class is created and assigned a subclass by the Player class and stored in the Player class. The subclasses that inherit the Cards class will call upon the functions of the Player class. I'm having a tough time making sure the 2 classes identify each others classes.

In that case, a forward declaration of a C++ class will just tell the compiler that the type you're using is a class.
This is often useful for headers, as you only need to know that the type is a class. Including the class' header would take more compile time.
But in the implementation, it's different. With a forward class, the compiler will not know about its members, methods, etc.
For that, you need to include the header file of the class.
For instance, with only the forward class, you can't do that:
owner->GetHealth();
As there is no way for the compiler to know the GetHealth method exists in your Player class, with just a forward class.
Note you may also have a problem in your AssignOwner method, as you implement it using your header. I'm a bit rusty on C++, as I'm doing C most of the time, but I think you should try declaring only the prototype in the class header, and implement the actual method in your implementation file, after having included the correct header file.

Forward declarations allow you to declare a pointer or reference to a type, but to actually use the pointer or reference you must have the full class definition. You also need the full definition for a member or local variable of the class type.

Related

Can Class Functions Have Parameters That Are Different Class Objects?

Let's say I have 2 classes, player and npc. In the header file for class player, could I have a function that has an npc class object as a parameter?
For instance:
player.h:
void somefunc(npc npc1);
Yes, this is allowed, as long as a definition or forward declaration for the type has been encountered yet. You can also have pointers or references to other types, and even parameters of the same class' type.
class A {};
class B {
public:
void funcA(A a) {}
void funcAPtr(A* p) {}
void funcARef(A& r) {}
void funcB(B b) {}
};
// ...
A a;
B b;
b.funcA(a);
This is actually one of the key tenets of object-oriented programming.
In your case specifically, you would want to have a definition for npc first, so it might look something like this:
// npc.h
class npc {};
// -----
// player.h
#include "npc.h"
class player {
public:
void somefunc(npc npc1);
};
Or, if you have function bodies in a .cpp file, you can just put a forward declaration in the header, and include npc.h in the source file. This is usually safer, especially in cases where you may encounter circular dependency issues.
// npc.h
class npc {};
// -----
// player.h
class npc;
class player {
public:
void somefunc(npc npc1);
};
// -----
// player.cpp
#include "player.h"
#include "npc.h"
void player::somefunc(npc npc1) {}
// Note that "npc"'s header must be included before the type is actually used.
// For example, it needs to be included before the function's body, even though a
// forward declaration is enough for the function's prototype to work properly.
Yes, it's totally possible and one thing I'd like to add is that is generally a good thing to receive the parameter as a pointer to a object of that class since you'll not always want to make a copy of an entire object in memory.
Besides that, you could (and should depending on the case) take the parameter as a pointer to a const object so that the method can access whatever it needs from the object without making a copy of it and without modifying it's members.

How do I need to declare a member class?

I need to use a custom exception class that's goign to be used from within member the function of the top-level class. So, it's reasonble to put the custom class as a member class. Here is the file where they're declared presently:
conductor.h:
class conductor
{
//some staff
private:
class bad_index : public std::exception
{
public:
bad_index(int);
virtual const char* what() const noexcept;
private:
int _idx;
};
};
I'm new to programming in C++ and still haven't learn how the C++ programmer're used to doing such things? Maybe we should put class bad_index as an incomplete type like that:
class conductor
{
//some staff
private:
class bad_index;
};
and make it complete and implement all member-functions in the cpp-file. What is the right way?
First of all, as bad_index is private, it can't be referenced outside the class, so it can't be used in exception handlers other than catch(...). If it's not really needed (that is, the exception is made only for internal use), perhaps it's enough to not make it a nested class but to define bad_index in the implementation file in namespace { ... }.
In case that bad_index is actually public, technically you can declare it in .h file and define in .cpp file, but it will again be unusable in catch clauses of class users, because you can't catch an exception of incomplete type even by reference, all you can do to catch it is again catch(...).
If the class is not part of public interface of your top level class then it makes sense to put al little information about it into the header file as possible and forward declaration does that job well. However if all the code that uses that exception is in one cpp file then you could as well avoid mentioning it in the header at all and declare in an anonymous namespace inside the cpp file.

Why are these classes incomplete?

I have a source.C:
#include "image.h"
#ifndef SOURCE_H
#define SOURCE_H
class Source
{
private:
Image* img;
public:
virtual void Execute()=0;
Image* GetOutput();
};
#endif
Image* Source::GetOutput()
{
return this->img;
}
and a sink.C.
#include "image.h"
#ifndef SINK_H
#define SINK_H
class Sink
{
private:
Image* img1;
Image* img2;
public:
void SetInput(Image* input1);
void SetInput2(Image* input2);
};
#endif
void Sink::SetInput(Image* input1)
{
this->img1 = input1;
}
void Sink::SetInput2(Image* input2)
{
this->img2 = input2;
}
I have a filter.h that I want to inherit from Source and Sink:
#include "image.h"
#include <iostream>
#include <stdlib.h>
class Source;
class Sink;
class Filter : Source, Sink
{
public:
Filter() {std::cout << "Constructing filter." << std::endl;}
};
However, the compiler gives me errors of invalid use of incomplete types 'class Source' and 'class Sink'. I also get an error of forward declaration for those same classes. The classes originally had their functions defined directly in public, so I moved them out, but that didn't help with this. Explicitly setting Source and Sink as public didn't help either. What's going on?
#include "sink.h"
#include "source.h"
should sort you out.
Also this line:
class Filter : Source, Sink
This is private inheritance, which is almost always what you don't want (you won't be able to use the class polymorphically).
You may need to change this to
class Filter : public Source, public Sink
It's because in your filter.h you are giving an incomplete declaration:
class Source;
class Sink;
but not defining them. The compiler needs to know the size of both in order to calculate the size of Filter in:
class Filter : Source, Sink
{
public:
Filter() {std::cout << "Constructing filter." << std::endl;}
};
The solution is to include the header files for both. And for that you'll probably need to separate declaration from implementation in header files and source files.
Forward declaration only lets compiler to know that a name exists, but it does not tell anything about the definition of the name. In order to inherit, the base class' definition must be known. You have to include the headers in filter.h so that compiler can see the definition of the parent classes.
Edit
Declaration means a name exists, definition means what the name looks like. For class definition, it means what the class contains, it's members, size etc. When a class is inherited by another, the compiler kind of places the members of base class in the derived class. So it has to know what the base class looks like. By including the header where base class is defined, compiler actually places the definition in the included file, hence it knows about the base class.
As others pointed out about your privately inheritance, I recommend you to read is-a has-a relationship and difference between private and public inheritance
There are two problems here
The first, as mentioned by others is that you need to include the headers for Sink and Source. At the moment you only have a forward declaration, which will let you use a pointer, but not derive from, or instantiate. The compiler doesn't know the size, or what methods it provides, or how to construct.
The second problem, which you will hit once you include the headers, is that the Sink class has a pure virtual function in it. This makes it an abstract base class.
You need to derive from this (which you have) and implement the Execute method in the derived class (which you haven't)

Using multiple classes within other classes

I'm finishing up a C++ assignment and I'm running into an issue with connecting all the classes together. The classes have basic constructors, getters, setters, etc. so I'm confident the abundance of compiler errors I'm getting are due to me mix and matching all of my Classes incorrectly...
My classes are split up into cpp and h files and I've basically used the include statements every time that class needs something from another class. A basic diagram of which class needs what is shown below:
Basically what I'm trying to figure out is if having #include "Product.h" in both CustomerOrder and Retailer is messing things up or if I'm doing this all the wrong way.
Any help would be lovely!
Thanks!
EDIT:
Here's one instance of what each class is basically doing. The Customer class holds an array of CustomerOrders and CustomerOrders holds an array of Products etc. etc..
...
class Customer
{
private:
string customerName;
string customerID;
float balance;
static const int ORDERSIZE = 2;
CustomerOrder* orderList[ORDERSIZE];
Retailer retailer;
...
and Customer Order:
...
class CustomerOrder
{
private:
static const int SHOPSIZE = 20;
Product* shoppingList[SHOPSIZE];
...
First of all, your diagram is confusing. In OOP, arrows like the one you use indicate public inheritance, but that doesn't seem to be the case here (nor that it should).
Your question cannot be answered generally. You #include another class if you need the complete type. Otherwise, a forward declaration will do. That only has an impact on compilation speed. Nevertheless, the rule is to use forward declarations if you can and #includes if you must.
Here are some cases where you can get away with a forward declaration:
1.) Pointers:
class AnotherClass; // <-- forward declaration
class Example
{
// ...
AnotherClass *another_class;
};
2.) References:
class AnotherClass; // <-- forward declaration
class Example
{
// ...
void f(AnotherClass &another_class);
};
3.) Return values:
class AnotherClass; // <-- forward declaration
class Example
{
// ...
AnotherClass Get();
};
As soon as you are actually using the object of the forward-declared class, you need to have the #include. If you forget, the compiler will remind you.
Caveat 1: Pay attention when you use forward-declared (i.e. so-called "incomplete") types in standard containers. Your compiler may allow this, but it's undefined behaviour to do so!
class Example; // forward declaration
std::vector<Example> v; // undefined behaviour!
Caveat 2: Don't attempt to forward-declare standard classes. Just do #include <vector>, #include <string> and so on and let the compiler figure out how to optimize compile time.
Edit: Actually, the linker, rather than the compiler, will remind you if you forget to include a forward-declared class you cannot forward-declare, but that's just a nitpick :)

What does the statement class foo; mean

I have been going through the code of a project and have encountered the statement
class foo;
.
.
.
.
foo* f1;
in various places. The class has not been declared in any of the headers included either. Can anybody tell me what that means.
It is a forward declaration. It can be used for classes, structs and functions, and it tells compiler that this is defined elsewhere or later.
For classes, there are (at least) two use cases.
1. Full definition not needed
After forward declaration, compiler does not know size or members of class, only name. That is enough for pointers to the class (and references which are basically syntactic sugar around pointers). But often pointer is enough, and then you can avoid including entire header file in another. This helps compilation speed, by avoiding need to recompile everything when one header changes.
myfuncs.h
class MyClass; // forward declaration
void helpMyClass(MyClass &needy);
// here this would give compiler error about incomplete type:
//void badHelp(MyClass needy); // value needs definition
myfuncs.cpp:
#include "myclass.h" // entire MyClass definition
void helpMyClass(MyClass &needy) {
needy.helpMe(false); // needs full definition
}
Important use case for this is the so called PIMPL idiom, also well covered here at SO under pimpl-idiom tag.
2. Two classes need to refer to each others
class node; // forward declarion
class collection {
node *frist; // pointer enabled by forward declaration
}
class node {
collection *owner; // already defined above so works too
}
In this case forward declaration is required to make this work nicely. Just saying in case you see it in the wild, there's the ugly way of using void pointer and casts, sometimes used when novice programmer does not know how this should be done.
I think you're referring to a forward declaration. It tells the compiler that a class named foo will be defined later. Until then it is an "incomplete type", meaning that pointers and references to the class can be defined. Instances of the class cannot be created until it is fully defined.
Your declaration is incorrect? I'm not sure.. I do know that you can't have "any" space "name".. Perhaps you missed an underscore?
I believe you meant:
class foo any_name();
In that case, it's forward declaring a function called any_name that returns a class instance of foo.
Example:
#include <iostream>
class foo any_name(); //The forward declaration..
class foo //the foo class implementation.
{
public:
foo(){std::cout<<"hey";}
};
class foo any_name() //The implementation of the function..
{
std::cout<<"any_name";
//return {}; //Can be used to return a constructed instance of foo.
};
int main()
{
any_name();
}