I have a class that should have a class of the same type as its member.
My declaration is the following:
class clsNode
{
private:
clsNode m_Mother;
public:
void setMother(const clsNode &uNode, int index);
};
C++ tells me "The object shows a type qualifier that is not compatible with the member function.
I don't know where I went wrong.
The reason is that the type of the member m_Mother has incomplete type at the point it is declared.
If you think about it. If it would have worked, you would create an object with an object inside with the same type, which in turn always have an object of the same type inside (and so on). The object would in a sense have infinite size.
One solution is to keep a pointer to the parent class instead.
class clsNode
{
private:
clsNode* m_Mother;
public:
void setMother(clsNode* uNode){ m_Mother=uNode; }
};
If you would like to have all parents always be alive during the lifetime of their children, you could use a shared pointer instead of a raw pointer.
class clsNode
{
private:
std::shared_ptr<clsNode> m_Mother;
public:
void setMother(std::shared_ptr<clsNode> uNode){ m_Mother=uNode; }
};
If you go with this solution you would originally create your objects with make_shared
You can't have a member of the same type inside the class. The compiler tries to calculate the size of the object and sort of "gets into a loop." You can get around that by using indirection. For example, you can store the pointer to the mother node.
class clsNode
{
private:
clsNode* m_Mother;
public:
void setMother(const clsNode &uNode, int index);
};
When you have a member of a class type (directly not a pointer), the instance of your mother class contains physically the contained instance.
In this case, the compiler can't find the size of the clsNode class as there's a cycle. It should contain a clsNode, which should contain a clsNode, and so forth.
Related
Let's say I have a class A that inherits from its parent class B, and there is another class C that also inherits from class B. Is there a way to change this pointer of class A to class C at run time?
class A : public B {
A::someFunction() {
//can I change this pointer to class C here?
}
}
class C : public B {
...
}
You cant and you shouldn't. The reason is pretty simple. Take a look at this code,
class Base {
public:
Base() {}
virtual void SayHello() {}
};
class A_Derived : public Base {
public:
A_Derived() {}
virtual void SayHello() override { ... }
void SayAllo() { ... }
};
class B_Derived : public Base {
public:
B_Derived() {}
virtual void SayHello() override { ... }
void SayBello() { ... }
};
Now when is we assign the A_Derived class pointer to B_Derived, the compiler will allow to call the SayBello method. This is because for the compiler, its a B_Derived class pointer, it doesn't know about the actual pointer data is pointing at a data block of A_Derived (because inheritance is not compile time, its runtime). So what happens when you call SayBello using that pointer? Its gonna be undefined behavior. You see the issue?
This is why you cant do it (logically and also using C++ style casting).
Is there a way to dynamically change an object to another type?
No. The type of an object cannot change through its lifetime.
Let's say I have a class A that inherits from its parent class B, and there is another class C that also inherits from class B. Is there a way to change this pointer of class A to class C at run time?
No.
At best, you could destroy the original object, and reuse its memory to create another object. Obviously the size and alignment of the memory must be sufficient for the new type. Any reference (which includes pointers such as this in a member function) to the old object will have been invalidated by the destruction of the original object. Reuse of storage is an advanced topic which I don't recommend to beginners.
There is no valid way to do this for one simple reason - in your class inheritance structure, an object of class A cannot be also an object of class C. In C++, two objects of different types can have the same address if and only if one of the objects is a subobject of the other, which is not your case. If you cast a pointer to A to a pointer to C, the pointer will still refer to an object of type A, and dereferencing the casted pointer would result in undefined behavior.
Most probably, what you want to do is to create an object of class C from an object of class A. You can use a converting constructor or a conversion operator to implement this.
Note that if what you really want is to reuse the storage allocated for the object of type A, you will still need to destroy the object A first and then construct the object C. You will have to save any relevant data from A before destroying it to be able to construct C with the data.
I use a library that only returns references to created objects Entity& Create(int id). In my class, I need to create one of these and store it.
I had thought to use class member std::reference_wrapper<Entity> MyClass::m_Entity but the problem is, I would like to create this object in a call to a method like MyClass::InitEntity() – so I run into a compile error "no default constructor available" because m_Entity is not initialised in my constructor.
Is there any way around this, other than to change my class design? Or is this a case where using pointers would make more sense?
Is MyClass in a valid state if it doesn't have a valid reference to an Entity? If it is, then you should use a pointer. The constructor initializes the pointer to nullptr, and the InitEntity function assigns it to the address of a valid Entity object.
class MyClass
{
public:
MyClass(): _entity(nullptr) {}
void InitEntity() { _entity = &Create(123); }
void doSomethingWithEntity()
{
if (_entity) ...
}
private:
Entity *_entity;
};
If MyClass isn't in a valid state without a valid reference to an Entity, then you can use a std::reference_wrapper<Entity> and initialize it in the constructor.
class MyClass
{
public:
MyClass(): _entity(Create(123)) {}
void doSomethingWithEntity()
{
...
}
private:
std::reference_wrapper<Entity> _entity;
};
Of course which one you go with depends on how MyClass is supposed to be used. Personally, the interface for std::reference_wrapper is a little awkward for me, so I'd use a pointer in the second case as well (while still ensuring that it's always not null).
I have a class and the constructor accepts a parameter. For example,
class Entity
{
private:
int number_;
public:
Entity(int number):number_(number)
{
std::cout << "Entity object created";
}
}
// header
class SuperEntity
{
private:
Entity *entity_;
public:
SuperEntity(int value);
};
// source
SuperEntity::SuperEntity(int value)
{
entity_ = new Entity(value);
}
class SuperEntity has a private member Entity. Since in order to instantiate Entity you need to pass in an int to it's constructor and cannot be done the declaration file (superentity.h) because the int value needed to instantiate Entity is not available yet, is it okay to dynamically allocate Entity in SuperEntity's constructor? Is this a bad practice? Thanks.
As Dietmar remarked, use a member initializer list:
class SuperEntity
{
Entity entity_;
public:
SuperEntity( int value )
: entity_{ value }
{}
};
It is ok per the language but not necessarily the best pratice.
Use an object if you can.
Failing that, use a smart pointer instead of a raw pointer. See std::shared_ptr and std::unique_ptr.
If you must use a raw pointer, make sure to follow The Rule of Three.
It's fine to have a pointer data field for a decoupled has-a relationship. If you really want to stick to pointers then you should prefer the std::unique_ptr to raw pointer and utilize the std::make_unique function in the member initializer list of the constructor:
class SuperEntity {
private:
std::unique_ptr<Entity> entity_;
public:
SuperEntity(int value);
};
SuperEntity::SuperEntity(int value)
: entity_(std::make_unique<Entity>(value))
{}
If you want to have a classic has-a relationship abstraction, namely a data field whose lifetime is bound to owners lifetime then loose the pointer and go with the object:
class SuperEntity {
private:
Entity entity_;
public:
SuperEntity(int value);
};
SuperEntity::SuperEntity(int value)
: entity_(value)
{}
};
The entity_ object will be destroyed once the object of type SuperEntity goes out of scope.
I'm new to C++ and have a question about member variable polymorphism. I have the following class definitions -
class Car
{
public:
Car();
virtual int getNumberOfDoors() { return 4; }
};
class ThreeDoorCar : public Car
{
public:
ThreeDoorCar();
int getNumberOfDoors() { return 3; }
};
class CarPrinter
{
public:
CarPrinter(const Car& car);
void printNumberOfDoors();
protected:
Car car_;
};
and implementation
#include "Car.h"
Car::Car()
{}
ThreeDoorCar::ThreeDoorCar()
{}
CarPrinter::CarPrinter(const Car& car)
: car_(car)
{}
void CarPrinter::printNumberOfDoors()
{
std::cout << car_.getNumberOfDoors() << std::endl;
}
The problem is when I run the following, the getNumberOfDoors of the parent class is called. I can get around this issue by making the member variable Car a pointer, but I prefer to pass in the input by reference instead of by pointer (which I understand to be preferred). Could you tell me what I'm doing wrong? Thanks!
ThreeDoorCar myThreeDoorCar;
std::cout << myThreeDoorCar.getNumberOfDoors() << std::endl;
CarPrinter carPrinter(myThreeDoorCar);
carPrinter.printNumberOfDoors();
By making a copy of the object you sacrifice its polymorphic abilities. Whatever type of car you pass, the copy will be of type Car (the base class), because that is what it is declared as.
If you want to keep using polymorphism either use a pointer or a reference. Here is the version using a reference:
class CarPrinter
{
public:
CarPrinter(const Car& car);
void printNumberOfDoors();
protected:
const Car &car_; // <<= Using a reference here
};
As you can see, this way you can continue using a constructor that takes a reference as argument. (These references don't have to be const, although const makes sense as long as the purpose of the CarPrinter is just printing.)
One potentially undesirable side-effect of this is that you can't change what the reference refers to after constructing the CarPrinter object. If you need to print the information for a different object, you'll have to create a new CarPrinter object for that. These objects would then really just act as (probably short-lived) wrappers around references.
If you don't like this, you can still continue passing a reference to the constructor, but turn it into a pointer by taking its address in the constructor implementation and then storing that.
When you do:
Car m_car;
It will not treat the m_car instance polymorphically, even if Car has subclasses and virtual functions. It will just use Car functions. This is called static binding - it determines which function to call at compile time based on the static type (Car) .
You need a reference or pointer for it to be handled polymorphically via dynamic dispatch by looking up the correct virtual function via the virtual function table of the instance's dynamic type (e.g. ThreeDoorCar or TwoDoorCar etc) at runtime. Polymorphic call behaviour is achieved through pointers or references in combination with virtual function declarations. This is more or less a direct result of syntactically using values vs pointers/refs (See #kfmfe04's comment below).
Car* pCar;
Car& rCar = x_car;
Virtual members called via a pointer or reference (e.g. pCar->getNumberOfDoors() or rCar.getNumberOfDoors()) does a vtable lookup at run time (dynamic dispatch). Because only at runtime does it know the dynamic type of the instance.
But m_car.getNumberOfDoors() is a virtual member that is called directly, and the compiler knows at compile time the direct (static) type and function address, statically binding the function address (Car::getNumberOfDoors) at compile time.
The problem is in this line of the CarPrinter constructor:
: car_(car)
This calls the compiler generated default copy constructor for the Car class, which ends up creating an instance of Car, not ThreeDoorCar.
Unfortunately, you'd need to pass the pointer, or pass by reference, but store the pointer. For example:
class CarPrinter
{
public:
CarPrinter(const Car& car)
:car_(&car) {};
...
protected:
const Car* car_;
};
I want to define an abstract base class with a vector of struct variables, and a virtual function to be implemented by derived classes:
class TestFather {
private:
struct myStruct
{
// struct definition
};
vector<myStruct> myStructVect;
public:
virtual vector<myStruct> get_myStructVect() = 0;
};
but when I write the derived class:
#include "TestFather.h"
class TestSon : public TestFather{
private:
struct myStruct
{
// struct definition
};
vector<myStruct> myStructVect;
public:
vector<myStruct> get_myStructVect();
};
I get this error:
invalid covariant return type for ‘virtual std::vector<ProvaSon::myStruct, std::allocator<ProvaSon::myStruct> > ProvaSon::get_myStructVect()’
Am I doing something wrong or maybe I'm trying to do something that is forbidden by the language?
The two myStruct types are totally unrelated. This means that you're trying to override TestFather::get_myStructVect() and have it return a completely different type. This is not allowed.
You don't have to redefine the struct in TestSon, and you also can't do this. The caller of fatherptr->get_myStructVect statically gets a vector<TestFather::myStruct> back, so the compiler forbids you to override the base class function like that, because the dynamically returned object would potentially be incompatible with vector<TestFather::myStruct> (who knows what you put into TestSon::myStruct and how vector differs in behavior from the base class vector?).
As for the allowed difference, C++ only allows the derived class return type to be a derived class of the base class return type, and only when the return types are pointers or references.
It's forbidden. Because you've redefined myStruct in your derived class, vector<myStruct> is a different type in the derived class than it is in the base class. They are two different myStructs.
You can only change the return type of that virtual function to something inherited from the return type declared in the base class. But vector<TestSon::myStruct> does not inherit from vector<TestFather::myStruct>
It says vector<myStruct> but since you changed myStruct in the child class it's actually two distinct types so each of the two functions thinks its returning a different type. This is only allowed for covariant types where the type is related to the actual type of the class containing the function.
Note that you probably shouldn't be returning a class attribute vector by value here anyway.
I can't tell what you really are intending to do, but the nested structures really shouldn't have the same name if they're two different things (and if they're the same, don't redefine it). My first gut reaction is that maybe the parent-child relationship isn't appropriate here. Have you considered other options? If you really need to return a different type in the child and the parent doesn't know about that, then you can't use a virtual interface to do this. You should just give the functions different names so you know what the return type should be.
With more details about your goals a better answer could be provided.
The duplicate private structure is a bit odd in your example. The below compiles fine, for instance:
class TestFather {
protected:
struct myStruct
{
// struct definition
};
vector<myStruct> myStructVect;
public:
virtual vector<myStruct> get_myStructVect() = 0;
};
class TestSon : public TestFather{
public:
vector<myStruct> get_myStructVect();
};
int main(int argc, char**argv)
{
TestSon testSon;
}
Note the replacement of private with protected, allowing derived classes access to the parent structure definition and myStructVect storage.