Say I have two classes with different names but the exactly same structure. It there a way to cast an object of the one class to one of the other?
This might sound stupid to do but there is a reason why I want to do that. The architecture of my application provides the abstract classes component and storage The ready application will contain several specialized components derived from component and each of them will define its own storage type, derived from storage. During initialization of the application, for each component there will be a storage object of its custom storage type created and passed as pointer to the component.
This way all component stay completely independent which is great for re-usability and testing. But, of course, there is a need to exchange informations between components. To do that with independence in mind, I want to let two components get a storage pointer pointing to the same storage. The pointer by constraint must be of the component specific storage type.
framework code (abstract classes)
class Storage {};
class Component {
public:
void SetStorage(Storage* storage);
private:
Storage* storage;
};
example component
class PhysicsStorage : public Storage;
class PhysicsComponent : public Component;
another component
class CollisionStorage : public Storage; // same structure as PhysicsStorage as both components need the same data like world coordinates and rotations of all forms in the 3d space
class CollisionComponent : public Component;
main application
#include "system.h"
PhysicsStorage Worlddata;
PhysicsComponent Physics;
CollisionComponent Collision;
Physics.SetStorage(&Worlddata);
Collision.SetStorage(&Worlddata); // this points to a PhysicsStorage but that is actually the same like a CollisionStorage which is expected
So I wonder if there is a way of casting the pointer of say PhysicsStorage* to CollisionStorage*. In this case, both are defined in the file of their related component class. And both are derived from abstract Storage.
I only want to do that in the case that both custom storage types have exactly the same structure. Otherwise it would be senseless. I am not so familiar with advances pointer usage so I wonder if there is a way to do that. What I know is that you can cast to a base class, but this isn't what I want here. Using a shared storage type for two components would break independence. Thanks a lot!
This may work, and it may not. I believe this is a case of undefined behavior, and I would avoid doing this in production code.
Consider instead pushing the common fields and methods up into a new class and having ComponentOneStorage and ComponentTwoStorage inherit that class. Then you can pass around pointers/references to the base class instead, which will give you access to the common data without having to cast between incompatible pointer types.
Related
If I have a class that inherits from a base class, can I use that base class as a variable type in c++?
class Component {
// Code here
};
class TransformComponent : public Component {
// Code here
};
class Entity {
// Code here
Component *getComponent(Component *searchComponent) {
// Code Here
}
};
as you can see here, I am using the base class "Component" as a return type and a variable type. The problem is that the user may input a "TransformComponent". The only reason I am asking this is because the "TransformComponent" class inherits from the "Component" class and there might be a way to do this?
<Entity>.getComponent(Component &TransformComponent());
The answer I'm looking for is one that works both for the return type, and the variable type.
Absolutely! It's one of the beauties of OOP. Your instanced class of type TransformComponent is both an instance of Component as well as TransformComponent.
If you had some function that returned a type of Component, this could return any class derived from Component as a Component! If you later wanted to refer to it as its sub-class, you might have to check its type and then cast to it, but what you want is absolutely possible, and you're going the right way about it.
In fact, in the example you describe, were you are using Component and the user might pass a TransformComponent, all of the base methods and properties that the Component possesses will be possessed by TransformComponent too. It will look and feel as if it was a Component, with all the benefits of being one.
The only time a problem will arise is if you specifically want to access the features of a TransformComponent, and the user passed a Component. The parent class doesn't know about the sub-class stuff, because it isn't an instance of one, it will throw up errors for you. Sub-classes build upon the base class, so they have all the base-class stuff, plus more. Basically its only an issue when your example is reversed.
Your Entity.getComponent() method suggests that it only cares that the provided argument is a Component ... not any specialization, such as TransformComponent, of that original class.
So, if you find yourself writing logic that actually cares that "this Component might actually be a TransformComponent," then "warning bells should be going off." Create method definitions within the class that are as specific as possible.
Root Problem
I am trying to build a render engine with Vulkan in C++. I am trying to remove the asset meshes, textures, and similar from within the engine structure where I had it for testing purposes to its own separate class. I need to access some of the objects stored in the render engine class because each asset need to be able to add themselves to the vector of vertices, and have access to the same VkDevice for example.
First attempt
The first method I tried was making the asset's constructor take the render engine as one of its arguments, then taking pointers to all the objects that I would need from the render engine for the asset. I still think that this method might work, but I could not declare the class for the render engine before the class for the asset because the render engine needs a vector of all the assets that it was managing in this scenario. Neither could I declare the class for the asset before the class for the render engine because then I could not take the render engine as an argument for the asset's constructor. This feels like it should have a trivial solution, but I could not find one, so I went off to try my second method.
Second attempt
The second method I tried was inheritance. However, I realized as I was experimenting with it that I did not know of a way to get one instance of the render engine class to be the parent of many instances of the asset class. Each asset wanted its own render engine, but I needed for each asset to inherit from the same render engine so that the render engine's objects would be the same for all assets and to avoid having many instances of the render engine to manage.
Final thoughts
I think that there is probably a simple way to do the first option, but I think that in the long run the second option will be more rewarding as it will be easier to manage, cleaner, lead to better organized code, and even teach me more about this great language that I am beginning to explore. I would prefer a solution that involves the second method, but I also don't really know if this is possible because it seems like inheritance does not work on a per instance basis. Finally, I am very much open to new ideas that do not involve either of these options.
Final question
Is there a method of going about inheritance that allows for many instances of one object to inherit from one instance of another object in C++?
Is there a method of going about inheritance that allows for many instances of one object to inherit from one instance of another object in C++?
No, you are mixing apples and oranges here.
Inheritance is a way to build one class off of one or more base classes. It has nothing to do with instances of those classes, and in C++ classes are not objects. So by deriving a class D from another class B you define D but you do not create any instances of either B or D.
When you create objects (instances) of D, these objects will all have the same binary layout that will include data members from B and D. That is, every object of class D will contain a base subobject of class B. You cannot create an object of class D without its base subobject of class B or with a different binary layout, e.g. by referencing B at a different address.
You could share data between different objects by using references or (smart) pointers, like std::shared_ptr. But this has nothing to do with class inheritance. You will have to use references and (smart) pointers as data members of your classes.
Can one instance of a class (not the class itself) be the parent of many instances of another class?
Technically yes... if those many instances are all sub objects within one complete object. Example (which is probably something that no one would ever write):
struct Base {};
struct Second : virtual Base {};
struct Third1 : Second {};
struct Third2 : Second {};
struct Derived : Third1, Third2 {};
Here, there is one instance of Base within Derived, and that Base instance is the (virtual) base of two separate instances of Second, both of which are indirect bases of Derived.
Even though the answer was "yes", I don't know if this would be of use in any use case.
I've created a C++ class that has a public member that is a pointer to an unrelated class. Here it is:
class ADS_1x15 : public Sensors {
public:
ADS_1x15(uint8_t addr = 0x48, adsGain_t gain = GAIN_TWOTHIRDS, String = "");
Adafruit_ADS1115* ads;
};
It's the base class for some other classes that do different things with the Adafruit ADS1115 ADC, so the member ads is used in any descendent class.
There is a very similar Adafruit ADC called an ADS1015, and I'd like for my classes to work with either of the two ADC's. Of course, an Adafruit_ADS1015 is a very different object than an Adafruit_ADS1115. In my base class, I want to be able to pass in a parameter that tells the class "include a pointer to EITHER an Adafruit_ADS1015 OR an Adafruit_ADS1115, but whichever one is used, make the variable name for the pointer be the same: ads". All the methods for the two objects are identical, so once I get ads pointed to the correct object, everything in my classes will work, regardless of which ADS is used.
Is this possible?
How to have a pointer to class A OR class B in my class?
Is this possible?
Yes. It is possible. You are describing dynamic polymorphism. If Adafruit_ADS1115 and Adafruit_ADS1015 share a base class B, then B* can point to (base sub object of) either child class.
There is also another form of dynamic polymorphism which doesn't require inheritance: Type erasure. There is unconstrained type erasure that can be achieved with std::any, which allows your class to contain objects of any type. And there is constrained type erasure that allows a finite set of types that can be achieved with a tagged union (std::variant). There are also specialised type-erasure wrappers for particular use cases such as std::function for storing any type of callable.
Note that dynamic polymorphism typically involves some amount of overhead which might not be necessary in your case.
An alternative is static polymorphism that can be achieved through the use of templates. In this case for example, you might define a following template:
template<class Adafruit_ADS1x15>
struct ADS_1x15 : Sensors {
Adafruit_ADS1x15* ads;
Suppose, that I have an abstract base State class and at least two derived classes AnimalState and PlantState(also abstract). Also, I have many derived classes from AnimalState and PlantState.
class State{} // abstract
class AnimalState: public State{} // abstract
class PlantState: public State{} // abstract
//maybe few more of such classes here
class AnimalStateSpecific1: public AnimalState{}
class AnimalStateSpecific2: public AnimalState{}
... //many of them
class PlantStateSpecific1: public PlantState{}
class PlantStateSpecific2: public PlantState{}
... //many of them
Now suppose, that I use them in some kind of method that operates on base State pointers. Those pointers are replaced over time with other pointers to different class from the State hierarchy. It happens by some rule, specifically within the predefined state graph.
Now to the question part. In order to determine the next state, I need to know the previous one. But since I have only base State pointers, I can not efficiently tell what type of state I have, without doing dynamic_cast to every derived class in the hierarchy that is not good. I can have some enum with all kinds of states that I have, but I do not really like that because I do not want to mix information from two hierarchy branches, as it is really different. Also, I do not like different enums for every branch in the hierarchy such as AnimalStateEnum, PlantStateEnum etc.
What is the best solution for this problem? Maybe my design is not good from the start? I want to keep it as generic as possible and work only with base class objects, if possible.
Now to the question part. In order to determine the next state, I need to know the previous one.
Simplest solution based on limited information we have - object, which knows it's own state creates next state object:
class State{
public:
...
virtual std::unique_ptr<State> transform( some data ) = 0;
};
then you implement it in each derived from State class which can change it's state and knows where it can move to. What data you need to pass is not a simple question - it depends on your task and may have various options, but you need to define something that can be used by all derived classes, as signature is defined on the base class and shared on all derived ones.
What is the best solution for this problem? Maybe my design is not good from the start?
This question is not trivial and only can be answered having pretty deep knowledge on your task. If you are unsure - implement a prototype and check if solution fits your problem well. Unfortunately the only way to learn how to create a good design is your own experience (except trivial cases of course).
You could simply have a virtual method next() inside the state class hierarchy,
and then do something similar to the following example:
State *globalState = nullptr;
void foo(State *s)
{
globalState = s->next();
}
Where each derived class will implement next() to its own meaning:
PlantStateSpecific1 *AnimalStateSpecific1::next(){ return new PlantStateSpecific1; }
AnimalStateSpecific1 *PlantStateSpecific1::next(){ return new AnimalStateSpecific1; }
This is more OOP than having an enum / integer descriptor of the derived class.
What you can have is an integer inside the base state class that every class below it will set in its constructor. Then you can either use a sereis of constants, a list of possible states with the id corresponding to the state type index, or use an enumerator.
The id is more flexible as you can create state types with relative ease and add handling to them without too much difficulty, aswell as if you want to create a new state from the id type.
Just one of the ways iv done this before, but there are probably many others.
I have recently been working on a C++ project that requires a system whereby classes can be stored in a map (a library). From my research, I have concluded that I need to use a pointer to an object of the class. That's fine, I have the object, however I need to make the pointer fit multiple different objects from different classes. If this is unclear, here is my code.
typedef NO-IDEA-WHAT-GOES-HERE;
struct library {
std::map<std::string, objPointer> lib;
};
I need to know how to create a pointer that can accept an object from more than just one single class, i.e.
//NOT WHAT I WANT
module someMod;
library *objPointer;
objPointer = &someMod;
But something more like...
typedef POINTER; //Not sure what to put here
module someMod;
std::map<std::string, POINTER> lib;
lib["something"] = someMod;
otherModule someOtherMod;
lib["somethingelse"] = someOtherMod;
Thank you in advance!
That's fine, I have the object, however I need to make the pointer fit multiple different objects from different classes.
This is a common pattern in many libraries and applications.
Create a namespace specific to your application.
Create an abstract class that can be used as the base class of all the important classes in your application.
Make sure that all the important classes are derived from the base class.
That will allow you to store pointers to instances of all the important classes in your application in whatever container you wish to store them.
Over time, you will find that you will be able to implement a lot of functionality using just the base class interface.