for example. We have class A and its derived class; class B. Is it possible to instantiate a pointer of type B in class A?
#ifndef WARRIOR_H
#define WARRIOR_H
#include "CharacterPlayer.h"
class Warrior: public CharacterPlayer
{
public:
virtual void printCharacterName();
};
#endif
however, when i try to instantiate a Warrior pointer or try to include "Warrior.h", it gives me a number of syntax errors.
#ifndef CHARACTERPLAYER_H
#define CHARACTERPLAYER_H
#include "Warrior.h"
class CharacterPlayer
{
public:
Warrior *warriorPntr = nullptr;
virtual void printCharacterName();
};
#endif
You have a circular dependency among your headers: "CharacterPlayer.h" includes "Warrior.h", and "Warrior.h" includes "CharacterPlayer.h". This cannot compile, because the "sentinel" will stop inclusion.
The trick is to forward-declare the Warrior class in the CharacterPlayer instead of including a header:
#ifndef CHARACTERPLAYER_H
#define CHARACTERPLAYER_H
class Warrior; // <<== Here
class CharacterPlayer
{
public:
Warrior *warriorPntr = nullptr;
virtual void printCharacterName();
};
#endif
This is good enough to declare pointers and references to Warrior, but not enough to call methods or instantiate the class.
You need to eventually include the header for Warrior in the cpp file CharacterPlayer.cpp, but that would not lead to any issues, because there is no circular dependency among your headers.
You can, but it's not a good idea.
To do it, simply remove the "#include "Warrior.h" from your second header, and replace it with a declaration of the form "class Warrior;"
As to why it is a bad idea: making a base class contain a pointer to (or an instance of) a derived class is one way (of several) that ensures implementation of the base class depends on implementation of the derived class. Generally speaking, the definition of derived class should depend on the base class, not the reverse, in order to avoid circular dependencies, to allow the base class to be used polymorphically (look up "Liskov Substitution Principle), etc etc.
This means, although it can be done, your design is fundamentally flawed. It would prevent you doing other useful things in future.
Related
I'm working on a simple C++ program and am having a difficult time understanding a compiler error I was getting. The issue was caused by me attempting to create a derived class from a base class. I've posted my code below with the same structure but have changed the names.
BaseClass.h
#ifndef BASECLASS_H
#define BASECLASS_H
class BaseClass {
public:
BaseClass(void);
virtual int method1(void) = 0;
virtual int method2(void) = 0;
virtual float method3(void) = 0;
};
#endif // BASECLASS_H
DerivedClass.h
#ifndef DERIVEDCLASS_H
#define DERIVEDCLASS_H
#include "DerivedClass.h"
class DerivedClass: public BaseClass
{
public:
DerivedClass(void);
};
#endif // DERIVEDCLASS_H
DerivedClass.cpp
#include "DerivedClass.h"
DerivedClass::DerivedClass(void)
{
}
int DerivedClass::method1(void)
{
// TODO
}
int DerivedClass::method2(void)
{
// TODO
}
float DerivedClass::method3(void)
{
// TODO
}
When attempting to compile this, I get the following error for all the virtual methods:
no 'int DerivedClass::methodX()' member function declared in class 'DerivedClass'
As soon as I declare these methods in the 'DerivedClass.h', the errors go away since the compiler is now aware of the methods.
However, I'm confused. Why was it necessary to re-declare the pure virtual functions in DerivedClass.h? When I #include DerivedClass.h, that will automatically include BaseClass.h, thus I assume my DerivedClass.cpp should be fully aware of the methods. Am I doing something incorrect?
It doesn't work this way. You need to declare the methods you're going to define, whether they're overriding a virtual method or not.
This isn't just an unreasonable requirement of the language. Without this you would be unable to define partially virtual class, i.e., you could have BaseSubtype that has common implementation of method1() but requires classes derived from it to implement method2() and method3()
When you declare a method in a derived class, you say to the compiler:
I want to override this method in this class
So if you don't declare a method in the derived class, you say:
I don't want to override this method; derived class's implementation is the same as the one in the base class
In your case, the base class declares them as pure virtual, so in this case it can be paraphrased:
I don't want to implement this method in this class
If you try to define a method but not declare it, you contradict yourself. The compiler detects that (to protect you from your own negligence).
A very non-intuitive reason why overridden virtual methods must be derived in the base class stems from the fact that C++ allows different parts of the class to be placed into different files, into different translation units.
With some other languages (I'm looking in Java's direction), a single class must be placed in a single file. This is not true with C++. It is perfectly legal for a class to have some of its methods declared in one translation unit, and other methods declared in another translation unit, which could be in a file in some different directory altogether.
Each such file gets compiled separately and individually. When compiling one translation, the C++ compiler has no knowledge of any other translation unit, any other file, that might contain other pieces of the same class.
Now let's say that you are allowed to omit an overriden virtual method from the class declaration. This creates an immediate problem: when compiling the class's constructor, it is necessary for the compiler to know whether the class overrides any virtual methods from any of the superclasses, in order to correctly assemble the virtual table dispatch for the class being constructed. Without an explicit declaration, the compiler has no way of knowing whether or not some other translation unit might define an overridden virtual method.
And that's why overridden virtual methods must be explicitly included in the class's declaration. In conclusion: because C++ formally specifies phase 9, the linkage phase, with the actual compilation carried on in earlier phases, overridden methods must be explicitly declared.
you should override all the base class pure virtual functions to be able to instantiate derived class.
you cannot define a base class member function from derived class.
in your example you are trying to define method1 and method2 and method3 which are not members of DerivedClass!! you have to declare them yourself in your derived class. compiler doesn't do it for you.
so your Derivedclass.h will look like:
#ifndef DERIVEDCLASS_H
#define DERIVEDCLASS_H
#include "BaseClass.h"
class DerivedClass: public BaseClass
{
public:
DerivedClass(void);
virtual int method1(void); // not pure function
virtual int method2(void);
virtual float method3(void);
};
#endif // DERIVEDCLASS_H
I have three classes:
BaseClass, that contains ElementClass as field
ElementClass, that contains BaseClass as field and ChildClass as return type (pointer)
ChildClass, that's inherits from BaseClass.
When I'm trying to compile this, I am getting
expected class-name before '{' token
for ChildClass, that was included in ElementClass, that was included in BaseClass.
I understand, why is this happens. Because I'm trying to inherit child class from nonexistent, for compiler, class BaseClass.
I can't understand hot to fix this. Thank you.
Here is code example with this problem
BaseClass.h
#ifndef INHERITTEST_BASECLASS_H
#define INHERITTEST_BASECLASS_H
#include "ElementClass.h"
class ElementClass;
class BaseClass
{
private:
ElementClass *m_someField;
};
#endif
ElementClass.h
#ifndef INHERITTEST_ELEMENTCLASS_H
#define INHERITTEST_ELEMENTCLASS_H
#include "ChildClass.h"
class ChildClass;
class ElementClass
{
private:
ChildClass *m_class;
};
#endif
ChildClass.h
#ifndef INHERITTEST_CHILDCLASS_H
#define INHERITTEST_CHILDCLASS_H
#include "BaseClass.h"
class ChildClass : public BaseClass
{
};
#endif
BaseClass, that contains ElementClass as field
ElementClass, that contains BaseClass as field
So, a BaseClass instance contains an ElementClass instance which contains a BaseClass instance which contains an ElementClass instance which contains... instances all the way down. One instance is going to use all of your memory and then some. That cannot work.
It also cannot work because when defining the first class, you need to have a complete definition of the second class, which needs a complete definition of the first class, which wasn't defined yet.
You must use indirection. At least one of the classes must not contain the other instance inside, but instead a pointer or a reference to an instance.
I have two questions
lets say there is a base class and several derived classes, the derived classes are going to have all of the #include statements (like #include <iostream> etc) and using lines of the base class.
1. is it considered a good practice to write the base class's #include statements and using lines in the in the derived classes h. file anyway?
2.same question regarding composition - class A has an object of class B as a member, is it a good practice to writes Bs#include` statements in A's h. file anyway?
thanks!
I think it is a good practice to have each include file actually #include any of the definitions it needs, so that in your main program, you can #include your most deeply derived class without having to have additional #include statements for the definitions that class needs.
You can have class definitions contain pointers to previously undefined classes, as follows:
class forward_ref;
class myClass :
Public:
myClass(){}
forward_ref* ptr_to_forward_ref;
};
lets say there is a base class and several derived classes, the
derived classes are going to have all of the #include statements (like
#include <iostream> etc) and using lines of the base class.
Not at all.
First of all, you are not supposed to put using lines at top-level scope in header files. This is a common beginners' mistake.
Second, what makes you think the derived class needs all #includes of the base class? The derived-class header file needs to include the base-class header file, and the derived-class implementation file needs to include the derived-class header file.
This already gives you all includes.
base.h:
#include <string>
class Base
{
// ...
virtual std::string f(); // no `using`
};
derived.h:
#include "base.h"
// no need for <string> here
class Derived : public Base
{
// ...
virtual std::string f();
};
derived.cpp:
#include "derived.h"
// no need for <string> here
std::string Derived::f() // could have used `using std::string`
{
// ...
}
Now of course, it's technically possible to actually do it otherwise, in a more complicated fashion, like this:
base.h:
// no <string>?!
class Base
{
// ...
virtual std::string f();
};
derived.h:
#include "base.h" // still no <string>?!
class Derived : public Base
{
// ...
virtual std::string f();
};
derived.cpp:
#include <string> // ah, OK
#include "derived.h"
std::string Derived::f()
{
// ...
}
This works only because the compiler doesn't separately compile header files but only compilation units (~= .cpp files) as a whole, after all includes have been processed.
But talk about horrible programming style. Why would you want to force everyone who derives from your class to include extra headers?
2.same question regarding composition - class A has an object of class B as a member, is it a good practice to writes Bs#include` statements
in A's h. file anyway?
It depends. If A's header needs access to any of B's members, then you have to use an include, and in that case, again, you just include what you need in b.h and let a.h #include "b.h".
If A's header only needs a pointer or a reference to B, or just a return value, then you can use a forward declaration in order to potentially speed up compilation. Of course, speeding up compilation is not something a C++ beginner should care about, because a lot of time will pass until you will be developing software which take hours to build :)
Anyway, for completeness' sake:
a.h:
class B; // forward declaration, no #include
class A
{
// ...
B f();
B *ptr;
B &ref;
};
a.cpp:
#include "a.h"
#include "b.h" // need the include here
B A::f()
{
B obj;
return obj;
}
b.h:
class B
{
// ...
};
In answer to question 2: typically you would include class B's header file in A's header file (so all the includes needed for A will automatically be included).
However, as pointed out in Logicrat's answer, you could alternatively include only a pointer to B in A. In this case you can use a forward declaration of B in A.h instead of including B.h. The downside to this is that all functions that need to make use of B must then go in A.cc (which will definitely have to include B.h). The advantage is that you can greatly reduce the quantity of code in the header files (since each #include copies an entire header file into the current file just before compilation), which can speed up compilation times.
I keep looking around fruitlessly for the solution to this,
I have a number of classes which inherit from one base class:
#ifndef navalVesselClass
#define navalVesselClass
#include <iostream>
#include <string>
class navalVessel
{
public:
std::string Name_;
std::string Type_;
std::string OperatingCountry_;
std::string Built_;
std::string ServiceDate_;
bool Active_;
double Length_;
double Displacement_;
double Beam_;
double Draft_;
double Speed_;
double Range_;
private:
};
#endif
and then, for instance a class that inherits it:
#ifndef destroyerClass
#define destroyerClass
#include "surfaceCombatant.h"
#include <string>
class destroyer: public surfaceCombatant
{
public:
enum class ArmamentPrimary { ANTIAIR, MISSILE };
enum class ArmamentSecondary { TORPEDOS, MISSILE, ANTIAIR, ANTIGROUND };
ArmamentPrimary primaryArmament;
ArmamentSecondary secondaryArmament;
private:
};
#endif
Now, When i want to STORE these objects in a vector i'm creating a vector as follows
std::vector<navalVessel *> shipFleet
Using that, i can store both, destroyers and other ships in this vector as pointers, HOWEVER once i try and retrieve them again, they are of course of the type 'navalVessel' and i cannot access any of the derived classes variables? e.g. primary weapon, i can only get access to the base class attributes.
Thanks.
Your design is flawed and you won't be able to do this without enabling RTTI and using dynamic_cast.
But this is useless as your design would remain bad or getting even worse.
I would suggest reading on some OOP basics as you do not fully understand the implication of base classes and polymorphism.
The idea of a base class is to provide a common set of methods which results in different values depending upon implementation of a concrete type.
In your scenario your base class should provide a member to obtain a list of possible weapons and every concrete implementation would return their set of weapons. Ships without weapons would return an empty list, etc.
But again. You have deep flaws in your understanding of abstract classes in C++. It is absolutely necessary to provide at least a virtual destructor in your base class.
Cast navalVessel* to pointer of whatever derived class the actual type is. Use a dynamic_cast.
So I have a vector of pointers to baseclass, which is used to hold all instances of derived classes.
Base class:
#ifndef BASE_H
#define BASE_H
Class Base
{
public:
virtual void DoSomething();
};
#endif
A derived class:
#ifndef DERIVED_H
#define DERIVED_H
#include "base.h"
Class Derived : public Base
{
public:
void DoSomething();
float y;
};
#endif
With these things being stored inside:
std::vector<Base*> theVec;
The question being, what is the best way to access the float variable "y" that exists only in Derived?
I could have a virtual function in Base that is specified in Derived to return a variable, where access looks like:
theVec[0]->GetVar("y");
but when Derived is likely to have multiple variables of different types that are not in base this seems like it will end up being quite messy. Are there any ways to make access to a unique variable in Derived more generic?
Any suggestions would be greatly appreciated!
You use dynamic_cast.
if (Derived* ptr = dynamic_cast<Derived*>(theVec[0])) {
// do something here
}
There is no elegant solution to this problem. If you have it, your design is probably flawed, and you should rethink it. Having special cases for sub-classes defeats the purpose of polymorphism (although I admit that sometimes it is the only solution).