std::shared_ptr Class Factory C++ - c++

We have a base class.....
class Node
{
public:
std::string Name;
Node(){};
~Node(){};
}
Filter is a derived class of Node.
Filter is the same a node, except it has a 'filterId' property and it's constructor populates Node.Name='Filter'.
class Filter: public Node
{
public:
int filterId;
Filter() : Node()
{
Name="Filter";
}
}
I have a ClassFactory that returns std::shared_ptr<Node> when passed a string
Please find the code to that factory on CodeProject following this link.
http://www.codeproject.com/Articles/567242/AplusC-b-bplusObjectplusFactory.
The code seems to instantiate a Filter, but, returns a Node. i.e. Object slicing.
std::shared_ptr<Node> n = std::make_shared(Node); // As expected, doesn't not have filter ID and node.Name is blank.
std::shared_ptr<Filter> f = std::make_shared(Filter); // As expected, has filterID and node.Name is 'Filter'.
Now i want to handle an array of std::shared_ptr(Node) which may actually contain std::shared_ptr(Filter) depending on what the class is requested from the factory.
std::shared_ptr<Node> nf = std::make_shared(Filter); // Error. Does not have filterId, but does have **Node**.Name='Filter'.
I even tried the simpler case..... and got the same problem.
Node n = Node();
Filter f = Filter();
Node nf =Filter(); // Error, nf does not have a filterID, but it's Name field is set to 'Filter'.
What am i doing wrong here? The Node is a base class for all of my derived classes. When i have a function that accepts a Node, i should be able to send it a Filter and have the filterId available.
Pointers are advised to help in situations like this, however the shared_ptr is a pointy as things will get.

Node doesn't have any knowledge of additional data members and functions that derived classes may define. So you need to retrieve a shared_ptr<Filter> to be able to access filterId. Use std::dynamic_pointer_cast to do this.
std::shared_ptr<Node> n = ...
auto f = std::dynamic_pointer_cast<Filter>(n);
if(f) {
// The managed object is a Filter
std::cout << f->filter_id << '\n';
}
Live demo
And if you know that n always contains a Filter (or something derived from Filter), you can use std::static_pointer_cast instead.

When you have any manner of pointer or reference to the base class, you can only access the things that the base class API exposes. If you want to access filterId, you need to either:
add it to the base interface (perhaps with a function that returns a boost::optional<int>, or pair true,filterId when available, otherwise e.g. false,0) or
see if you can std::dynamic_pointer_cast to the Filter type, if the returned pointer is true in a boolean context, you can use it to access the filterId.

Related

Is there a way to call derived class methods when iterating through base class references?

I have a base class Auto_Part and several derived classes like class Battery, class Engine, class Frame, etc. I also have a grandchild derived class Car that inherits all of the derived parts classes.
My goal: I have an Inventory class and an inventory object that is a map<Auto_Part*, int> . The first value is the Auto_Part reference being stored, and the second value is how many are there available in the inventory. The user should be able to create a car object using parts available in the inventory. I want to iterate through this map and use the appropriate accessor method to get the data needed to create my car object.
Here is the function in question. I'm trying to use the MVC model so it is a Controller function.
void Controller::add_car_from_parts(){
//All variables used in all of the parts
std::string type, frame_type, category, color, bolt_pattern, tire_type, speed_rating,load_range, w_frame_type;
std::string name, fuel_type, grip_type, horn_type, display_color, seat_material, seat_warmers, door_material, butterfly_doors;
int part_number, cranking_amps, cold_cranking_amps, voltage,diameter,width,ratio, w_diameter,w_width, num_doors,
length,reserve_capacity_minutes,num_cylinders, steering_wheel_diameter, num_seats, display_length;
double price;
int quantity;
Dialogs::message("You will be shown the parts available in the inventory. Please write down the part number of the part you will add to you vehicle.", "PART NUMBER");
view.view_all_inventory();
part_number = view.pn_prompt();
//quantity = view.quantity_prompt();
for(auto x: inventory.get_inventory()){ //inventory is a map<Auto_Part*,int>
if (x.first->get_part_number() == part_number){ // If part is in the inventory
if (x.first->get_type() == "Battery"){// and if the part is a battery, auto_part function available in all auto_part classes including class Auto_Part
name = x.first->get_name(); // auto_part function, available in all auto_part classes including class Auto_Part
price = x.first->get_price(); // auto_part function, available in all auto_part classes including class Auto_Part
cranking_amps = x.first->get_cranking_amps(); // battery function only
cold_cranking_amps = x.first->get_cold_cranking_amps(); // battery function only
voltage = x.first->get_voltage(); // battery function only
reserve_capacity_minutes = x.first->get_reserve_capacity_minutes(); //battery function only
inventory.remove_parts(x.first,1); // removes part from inventory, second value is quantity removed
}
}
}
}
So x.first->get_part_number(), x.first->get_type(), x.first->get_name(), and x.first->get_price() work fine because they are in the Auto_Part class as well as in all of the derived classes and so when iterating through it points to the appropriate get function. The first error is at the line cranking_amps = x.first->get_cranking_amps() and my compiler says "class Auto_Part has no get_cranking_amps() function, only battery function."
I thought that since the map is made of Auto_Part* and not just Auto_Part objects, it would reference the appropriate class. As in the x would change as it iterated through the map to a Battery object or an Engine object depending on what it was, and I could therefore use its unique functions. How do I call the derived class functions while iterating through this list of base class references? Surely, I don't need to create each of those derived class functions in the base class, right? That seems like it would defeat the purpose of having derived classes with unique functions.
Thank you for your time.
The compiler has no idea that get_type() == "Battery" has any relationship to class Battery. You still have just a Auto_Part*.
If you want to use members not reachable through Auto_Part*, you have to do the type conversion yourself, using a cast:
auto superclass = x.first;
if (superclass->get_type() == "Battery") {
name = superclass->get_name();
price = superclass->get_price();
Battery* subclass = static_cast<Battery*>(parent);
cranking_amps = subclass->get_cranking_amps();
cold_cranking_amps = subclass->get_cold_cranking_amps();
voltage = subclass->get_voltage();
reserve_capacity_minutes = subclass->get_reserve_capacity_minutes();
inventory.remove_parts(superclass,1);
}
But, when using the type system, you don't even need a get_type() function, you can use a runtime type check:
auto superclass = x.first;
auto as_battery = dynamic_cast<Battery*>(superclass);
if (as_battery) {
name = superclass->get_name();a
price = superclass->get_price();
cranking_amps = as_battery->get_cranking_amps();
cold_cranking_amps = as_battery->get_cold_cranking_amps();
voltage = as_battery->get_voltage();
reserve_capacity_minutes = as_battery->get_reserve_capacity_minutes();
inventory.remove_parts(superclass,1);
}
The dynamic_cast will evaluate to a null pointer if the runtime type doesn't match.
As #davidbak says, the Visitor pattern is designed to solve this problem in a more maintainable way (although there's a bit more code up front).

Converting subclass to base class?

I am working on a problem in which we have a binary search tree made of nodes. The node's attributes consist of string, pointer to left node, and pointer to right node. I have a class called TransactionNode that is a subclass of node. TransactionNode has an int (for amount sold) as well as the same attributes from node class. I have a function called findBiggest that looks for the highest amount sold from TransactionNode and returns a reference to that TransactionNode. My problem is how do I convert something that is from the node class to TransactionNode? (I am avoiding changing the nodes in the binary search tree to TransactionNodes)
TransactionNode & BST::findBiggest()
{
TransactionNode * rightSide;
rightSide = this->mpRoot;
while (rightSide != nullptr)
{``
//find biggest transaction
}
return rightSide;
}
In general, if you need to check if an object pointed to by a base class pointer is of the derived class type, you use dynamic_cast
In your case you could try inside your while loop:
TransactionNode* txnNode = dynamic_cast<TransactionNode*>(rightSide);
if (txnNode != nullptr)
{
int amtSold = txnNode->GetAmountSold();
}
You may also consider having a virtual method in the base class and rely on polymorphism. Usually that is a preferred way over dynamic_cast. However, it may be that your Node class is too high level and does not need to support a "GetAmountSold()" method, but that is something you can decide.

Cast Object at Runtime Depending on Instance Variable (C++)

I'm trying to represent a 2 dimensional map of objects. So I have a two-dimensional array of "MapItems":
MapItem* world_map[10][10];
In my specific situation, these MapItems are going to be used to represent Drones, Static Objects (like trees or any obstruction that doesn't move), or empty positions (these objects will be subclasses of MapItem):
class Drone : public MapItem {
int droneId;
...
}
class StaticObject : public MapItem {
...
}
class EmptyPosition : public MapItem {
int amount_of_time_unoccupied;
...
}
Is it a good idea to have an instance variable on the MapItem class that tells what specific type of item it is, and then cast it the proper type based on that? For example:
enum ItemType = {DRONE, STATIC_OBSTRUCTION, EMPTY};
class MapItem {
ItemType type;
...
}
And then when I want to know what is at a position in the map, I do:
MapItem *item = world_map[3][3];
if (item->type == DRONE) {
Drone *drone = dynamic_cast<Drone*>(item);
// Now do drone specific things with drone
...
} else if (item->type == STATIC_OBSTRUCTION) {
StaticObject *object = dynamic_case<StaticObject*>(item);
// Static object specific stuff
...
} else {
...
}
I have not actually tried this, but I assume it's possible. What I'm really asking is this a good design pattern? Or is there a better way to do this?
A "switch on type" indicates a design problem much more often than not.
What you usually want to do is define and implement some virtual functions for the behaviors you care about. For example, you might care about flying into one of the spaces. If so, you might have a function to see if it allows entry. That will return true if a drone is trying fly into open air, or false if it's trying to fly into a tree.
As an aside, if you're going to have derived objects, you need to define the array as container pointers, not actual objects of the base class. Otherwise, when you try to put a derived object into the array, it'll get "sliced" to become an object of the base class.

Common interface for all derived classes

I have base class Item which store some data and grant access to it by accessors, like:
class Item{
(...)
public:
int get_value();
double get_weight();
ItemMaterial get_material();
(...)
}
Then I've got derived classes like Weapon, Armor which add some additional data:
class Weapon : public Item {
(...)
public:
int get_dmg();
(...)
}
I store these Items in some container:
std::vector<Item*> inventory;
And here comes the problem with interface - how to get access to derived class data? I was thinking, and got 3 ideas:
1. Separate interfaces
Each derived class adds its data, like it is shown above, and then use dynamic_cast:
Item *item = new Weapon;
int dmg = dynamic_cast<Weapon*>(item)->get_dmg();
2. Common interface class
Make an interface class with all accessors:
ItemInterface{
public:
virtual int get_value() = 0; //Item interface
virtual double get_weight() = 0;
(..)
virtual int get_dmg() = 0; //Weapon interface
(...)
}
And then something like this:
Item : public ItemInterface{ (...) }
and
Weapon : public Item { (...) }
and finally we can access the data:
Item *item = new Weapon;
int dmg = item->get_dmg();
3. Combination with templates and enums
This idea is maybe a little weird :-) but:
implement enum with all item data:
enum class ItemData{
Value,
Weight,
Material, //Item data
(...)
Damage, //Weapon data
(...)
Defense, //armor data etc.
(...)
Null
}
and in base class some template function like this:
template<typename T>
T get_data(ItemData data){
switch(data){
case ItemData::Value: return _value; break;
case ItemData::Damage: return _dmg; break;
(...)
}
}
and access data like:
Item *item = new Weapon;
ind dmg = item->get_data<int>(ItemData::Damage);
===
How do you think it should be done? I will be grateful for any advices!
Regards.
Your second and third option is obviously not the way to go - whenever you add a new type of item, you will also have to change the base class or the enum - that is definitely not what you want to if you need any basic form of maintainability in your code.
And here comes the problem with interface - how to get access to derived class data
First you have to think of "where will your code do this"? Most of your code dealing with the whole inventory should only use the content as Item*, using only functions from the Item class.
If you have code specificially dealing with Weapon objects, the place where the Weapon objects are created (and inserted into the inventory), may also add them to another variable, maybe a weapons list in form of a
std::vector<Weapon*> weapons;
or to a member variable Weapon* of a class Warrior or something like that (but beware, you now will have two pointers to the same objects, so you have to think about ownership). So the code dealing only with weapons (for example, a member function of Warrior) does not access the inventory to get a Weapon object, it will always use the Weapon* directly.
If, for some reasons, you have to write some code which does something for all weapons from your inventory, then write a single function which extracts all Weapon objects using the dynamic_cast (or even better: make it an iterator function), and reuse this function whenever you need to get access to all weapons. So you don't clutter your code all over with dynamic casts, but keep this in just one place.
EDIT: another alternative (avoiding the dynmic cast) is using the visitor pattern, see this post. But I don't really like the answer of that post, in the presented form it will imply a cyclic dependency "Base -> Visitor -> Derived -> Base", which is IMHO a bad design.
ValueType Weapon::getProprtyValue( PropertyType id ) {
switch( id ) {
case kWeaponProperty01: return m_weaponProperty01;
...
default: return Item::getPropertyValue( id );
}
}
You can make some kind of universal accessor method, though it have some limitations, it could be quite handy, especially in case of content editors, serialization etc.

Class containing the instance of same class type

I have the requirement to contain a pointer of same class within a class ( something like link list , containing the pointer to next link ). What my requirement is something like this :
class A
{
class A* child;
}
I want to ensure that A->child->child will always be NULL and no one can change this. ( Ensuring a link list to have no more than two nodes ).
Any help ?
Any restriction like that would be awkward (if possible). I'd go with a fixed-length array instead:
A* l[3];
if you need to prevent slicing, or simply
A l[3];
otherwise.
You could programatically enforce that restriction through something like:
class A
{
A* child;
public:
void addChild(A* newChild)
{
if ( child == NULL )
child = newChild;
else if ( child->child == NULL )
child->child = newChild;
else
throw std::exception("list is already at full capacity");
}
}
It can't be done, not using a single link anyways. If you have a link pointing back to the "parent" it might be done by having the child and parent member variables private, and then have special access functions that makes sure you can not add more than two links to the first object in the chain.
The reason I suggest using a "parent" chain is because you could force the first object in the chain to check it's child chain, but if you have access to e.g. the last object in the chain you could add two more children in that chain.