I have a class, describing some object with properties, e.g. inventory item.
And along with default constructor, I need parametrized constructor, to create items with certain set of parameters, for example, size)
UCLASS()
class xxx_API UItem : public UObject
{
GENERATED_BODY()
public:
UItem();
~UItem();
UItem(int _size);
UPROPERTY(BlueprintReadOnly, Category = "Parameters")
int size = 0;
};
And I have another class, which I want to serve as container for pre defined items, so I can have references to it from other places of the game.
UCLASS()
class xxxx_API UItemsContainer : public UObject
{
GENERATED_BODY()
public:
UItemsContainer();
~UItemsContainer();
UItem SomeItem = UItem(100);
};
So I can at the begiining of game create this item container
ItemsContainer = NewObject<UItemsContainer>();
And then add it to some item collection of certain entity like this
TArray<UItem*> CharacterItems = {};
CharacterItems.Add(&ItemsContainer.SomeItem);
Since items are fixed and will not change during game, I dont want to create specific object for each of them, and just have references to container entries.
Though on compilation I get error, that I try to access private members of UItem class. Though, it's constructor is public and all properties are public. I think that there is something in UClass, that dont allow me to use constructor that way, since I can do this with objects, that are not UObject. But I need it to be UObject, to be usable in blueprints. And I dont know how to call non-default constructor in other way.
Probably I can create default object with NewObject, and then initialize it and store in array, but looks like there will be too much code and complication.
Any suggestions please?
Because C++ has been stylized in Unreal, e.g. auto generated source file of UItem is in the directory:
MyProj\Intermediate\Build\Win64\UE4Editor\Inc\MyProj\Item.generated.h
You can open this source, the copy-constructor of UItem has been shadowed, and UItem SomeItem = UItem(); would trigger copy-constructor, so you will get a compilation error that try to access private members of UItem class.
In Unreal, you must invoke NewObject when creating UObject, e.g.
SomeItemPtr = NewObject<UItem>(Outer);
If you want to pass parameters on creating UObject, you can define a specific function
void UItem::SetParams(int Size)
{
//initiation ...
}
e.g.
UItemsContainer::AddItem(int ItemSize)
{
SomeItemPtr = NewObject<UItem>(this);
SomeItemPtr->SetParams(ItemSize);
}
Related
Imagine that you're making a GUI and have a DataViewList class that is a widget that displays rows of data (like this for example). You have methods AddRow(std::vector<std::string> row), DeleteRow(std::vector<std::string> row) and AddColumn(std::string name), DeleteColumn(std::string name).
Now lets say you want to make a new class that displays a music playlist. It has predetermined columns (Title, Album, Year) and you don't want to ever add any new columns or delete existing ones. Also you want to be able to add Song objects to the list in a single method call, so you need a method that can do that. How do you implement such a class?
The most basic idea is to just create a new class MusicPlaylsit that inherits publicly form DataViewList and add the predetermined columns in the constructor. Then overload the AddRow methods such that it accepts Song objects as an argument. This approach has a big problem: Someone could call MusicPlaylist::AddColumn or other methods that are incompatible with the logic of the MusicPlaylist class. Since MusicPlaylist should only ever have the three predefined columns, then there shouldn't be a way to add or delete columns (or access any other incompatible base class methods such as the base class non-overloaded AddRow method).
To solve this, I can use composition instead of inheritance and re-implement any methods that I may want to use. In my opinion this is a bad idea because if I want to change something in the future, it's more difficult than inheritance because I cant override the base class methods.
Another option is to inherit as protected. This prevents using incompatible base class methods AND allows for overriding in case of future inheritance. The problem is, now I have to explicitly declare every method I want to use as public with using, which seems to be against the whole point of object oriented programming (being able to change something in a deep base class and still have any inherited class be able to use it) because newly added public methods in DataViewList will not be visible in MusicPlaylist or any classes that inherit from it until they have been explicitly made public.
So my question is: which pattern should I use when creating a new class that has an "is a" relationship to a base class, but is only partially compatible with it's methods?
Thanks
Let's step back and look at your design again:
class DataViewList {
using Col = std::string;
using Row = std::vector<std::string>;
virtual void addRow(Row) = 0;
virtual void deleteRow(Row) = 0;
virtual void addColumn(Col) = 0;
virtual void deleteColumn(Col) = 0;
virtual void draw(Context) = 0; // not in your question, but inferred
};
What you want to do is:
class MusicPlaylist : public DataViewList { /* ... */ }
And you discovered this cannot work, because MusicPlaylist does not fulfill the contract defined by DataViewList. Let's review this. What are the responsibilities of DataViewList?
It draws.
It provides a list of items.
It modifies that list of items.
That's 3 responsibilities. That violates 2 of the SOLID principles:
A class must have only one responsibility (Single-responsibility).
Consumer must not be forced to depend on things they do not use (Interface segregation).
And this is why you have a problem: MusicPlaylist only cares about 2 of those responsibilities, drawing and maintaining a list of items. It does not maintain a list of fields, and thus cannot inherit DataViewList.
How to fix?
Split the responsibilities.
// An interface for a data grid. Only provides a read-only view. No drawing.
struct DataList {
virtual const std::vector<Column>& getColumns() const = 0;
virtual const std::vector<Row>& getRows() const = 0;
protected:
~DataList(); // or make it public virtual to be able to delete a DataList*
};
// The widget that draws data.
class DataViewList : public Widget {
public:
virtual void setData(const DataList&); //could be a pointer, YMMV
virtual void draw(Context);
};
Note how:
DataViewList no longer contains any data, instead it will reference some other object that contains the data.
As it only shows the data, it depends on a simple interface that only contains reading functionnality.
At this point you can simply make a:
// Contains music data - does not draw it
class MusicPlaylist : public DataList {
void addSong(Song);
void deleteSong(Song);
const std::vector<Column>& getColumns() const override;
const std::vector<Row>& getRows() const override;
};
// Contains more complex data with configurable columns - does not draw it
class SomeMoreComplexList : public DataList {
void addColumn(Col);
void deleteColumn(Col);
void addRow(Row);
void deleteRow(Row);
const std::vector<Column>& getColumns() const override;
const std::vector<Row>& getRows() const override;
};
That is, your lists implement the interface that the widget requires to be able to display them, plus whatever specific functionality they need. You can then give them to the widget's setData.
There is no "partially is-a" relationship. Either MusicPlaylist can do everything a DataViewList advertises, or MusicPlaylist is not a DataViewList.
DataViewList advertises to be able to AddColumn. Perhaps it is too optimistic a promise. Most kinds of data only have fixed sets of columns that make sense, so perhaps AddColumn should be moved to a separate subclass of DataViewList. Say, EditableColumnsDataViewList?
On the other hand, perhaps it is not such a big deal to allow users to add columns to any kind of data. Maybe you think that columns like colour or shape or distanceFromParis don't make much sense for a song, but what if your users have different ideas?
So I got the following Structure.
abstract class Item {}
abstract class ICarriable {}
class Apple : public Item {}
class Stick : public Item, public Carriable {}
// More Items which may or may not derrive from Carriable
class Pants : public Carriable {}
Stick* StickyStick = new Stick();
Pants* CoolPants = new Pants();
void Equip(ICarriable* ItemToEquip) {
// Do things here
}
Equip(StickyStick); // Allowed.
Equip(CoolPants); // Not Allowed.
Now I want a function where I can pass Items which implements Carraible. So that I can pass Stick but not an Apple.
I try to avoid an if inside of that function in case the Item cant be cast to Carriable.
To me it's not clear why you would want this and I think it is a design flaw. Why would an Equip function that only uses the Carriable interface functions why does it need the parameter object to also be an Item? Does the function need Item specific functions? If you want it to just satisfy the requirement of both being an Item and Carriable you could just make a third class like 'Equipable' and let that inherit from both.
I have a base model where I have implemented the virtual members of QAbstractItemModel. I then use my base model in my project as needed by deriving new classes with specifics.
class BaseModel : public QAbstractItemModel{
public:
...
protected:
QList<BaseItem*> list;
}
class DerivedModel : public BaseModel{
public:
...
}
class DerivedItem : public BaseItem{
public:
...
}
My derived model uses DerivedItem objects to store data which have some specifics that BaseItem doesn't have. They are stored in list. Methods in BaseModel uses objects in list as well.
My issues is because of this I have to type cast every time I access objects from list in the derived model. And I can't use macros like foreach.
Is there any tips or tricks I can use in this circumstance that will enable me to use macros and prevent me from type casting every time I access items from the list. Or is there another method (better practice) when making a common class to later derive from.
Thanks,
when BaseItem has virtual methods and DerivedItem does only overwrite the existing members of BaseItem you should be able to call
foreach(BaseItem* item, list){
item->foo();
}
because of polymorphism, item->foo() will call DerivedItem::foo() if it is of that type otherwise it will call BaseItem::foo()
I have a scene graph, all nodes deriving from a base class AbstractNode. AbstractNode has a registerChild member function:
registerChild<T>(string name, shared_ptr<AbstractNode> * childMember)
used for registering the children in a standard way (so that they can be listed and modified in the base class interface). It basically adds the name/child_pointer pair to a hash.
So for instance the class material will be declared like that (shortened):
class Material : public AbstractNode
{
public:
Material() { registerChild(&color); }
private:
std_shared<Color> color;
}
Color being another subclass of AbstractNode.
Now I would like to implement a copy constructor for AbstractNode. It must copy the list of registered children, and update the child member pointers. I would like to avoid reimplementing the copy constructor in all base classes. Is this possible?
I have thought of working on pointer offsets, between this and the child pointers. But are these guaranteed to be constant between two instances? It seems like a big hack to me... (And I'm even sure that this is not guaranteed when subclassing)
Thanks,
Etienne
I'm trying to create a master-slave scenario where the first class contains a list of all the other sub classes. I've created two classes.
If my master class is ControllerDetail and my sub class is ControllerPOD: public ControllerDetail....can I create a list of all ControllerPOD's from the Controller Detail class?
I've tried creating std::list<ControllerPOD> cps; in the private section, but that obviously doesn't work.
Thanks!
Yes, you can:
class ContollerPOD; //forward declaration
class ControllerDetail
{
...
private:
std::list<ControllerPOD> cps;
};
class ControllerPOD: public ControllerDetail
{
...
};
It is slightly ambiguous what you are trying to do here. ControllerDetail is a class not an object, and you will have lots of them, one for each ControllerPOD.
So if you want it to have a list it would have to be static.
Now suppose you want ControllerDetail to have a static list of all the objects currently existing that derive from it. So we will have this:
class ControllerDetail
{
typedef std::list<ControllerDetail * > list_type;
static list_type instances;
list_type::iterator m_iter; // will become apparent later
};
In our constructor of ControllerDetail we will add our instance to the list.
ControllerDetail::ControllerDetail()
{
instances.push_back( this );
m_iter = instances.back(); // iterator that holds our object
}
In our destructor we remove ourselves from the list
ControllerDetail::~ControllerDetail()
{
instances.erase( m_iter );
}
And obviously you may have to handle thread-safety issues in all of this but you can iterate through the list and see all the current instances of the class. As ControllerPOD derives from ControllerDetail, when it is constructed it will get added too.
If you only want specific sub-classes to be added, you can use some kind of flag in the constructor of ControllerDetail as to whether to add itself.
It is generally better for a class to not know the classes that derive from it.
Now if ControllerPOD is not really a type of ControllerDetail then your ControllerDetail would have a list of ControllerPOD* instead, your ControllerPOD constructor would instead add itself and remove itself from the list, and you would have to sort out your "access" to allow it to do so, but the principle is the same.
If your ControllerPOD is passed a "parent" object which is a ControllerDetail, then the parent would have the list as a member and your ControllerPOD would add itself and remove itself from the parent's list. This assumes the parent outlives the child.
If we see what you really want to do, we can look at your class design a bit more clearly.