This question already has an answer here:
can dynamic binding happen without using pointer and using regular object in c++
(1 answer)
Closed 4 months ago.
I am trying to find a way to create a generic "car" class, with children that overload the parent's methods. Subsequently, I would like to have a user class that has as a member any class in the "car" family. Is there a way to achieve the desired functionality? Thank you!
The pseudocode below shows what my intial attempt was, but the compiler obviously complains that User wants a Car object, not a Toyota.
class Car
{
public:
Car();
void method1();
};
class Toyota : public Car
{
public:
Toyota();
void method1();
};
class Lada : public Car
{
public:
Lada();
void method1();
};
class User
{
public:
User();
Car car;
};
int main()
{
User user;
Toyota toyota;
user.car = toyota;
}
There are several ways to achieve this. One approach is to use pointers or references which allow you to use runtime polymorphism. A pointer or reference to a Car can also point to any object of a class derived from Car. However to get true polymorphism you need to declare the methods virtual. Also you really should delcare a virtual ~Car() = default destructor:
struct Car {
virtual ~Car() = default; // virtual destructor is important if you
// hold owning references or pointers that
// you want to use to destroy the object
// (like for example std::unique_ptr)
virtual void method1(); // declare this virtual if you want
// polymorphic behaviour on method1
};
struct Toyota : public Car {
void method1() override; // no need to declare this virtual because
// it is already virtual in base class.
// the 'override' would warn you if there was
// no 'virtual method1' in the base class
};
// ...
Toyota toyota;
Car& car_ref = toyota;
Car* car_ptr = &toyota;
car_ref.method1(); // calls Toyota::method1()
car_ptr->method1(); // calls Toyota::method1()
If using references or pointers you should keep in mind that they are non-owning. You must ensure, that the object that is referenced exists if you dereference the pointer or reference.
Car& f() {
Toyota toyota;
Car& car_ref = toyota;
return car_ref; // badooomz: return of reference to toyota
// that is going to be destroyed at the end
// of scope. You do not want this
}
An easy way to couple ownership to a pointer is to use std::unique_ptr:
std::unique_ptr<Car> f() {
auto toyota = std::make_unique<Toyota>();
return std::move(toyota);
}
An entirely different way to achieve your goal is to use static polymorphism (or duck typing) through std::variant:
struct Car {
void method1(); // no virtual functions needed
};
struct Toyota { // note: no inheritance here
void method1();
};
// ...
Toyota toyota;
// store a toyota in the variant
std::variant<Car, Toyota /*,...*/> car = toyota;
// call Toyota::method1()
std::visit([](auto&& car_like){ car_like.method1(); }, car);
Note that there is no relationship at all between Car and Toyota in this example. You could store any object in the variant, for which obj.method1() is a valid function call. That is why this kind of static polymorphism is called duck typing - anything that looks like a duck is treated like a duck. Note that when using std::variant you store a copy of the object and not a reference in the variant. Thus it is safe to return the variant from a function even if the original object is destroyed when leaving the function scope.
i think you should use virtual functions inside car and a reference pointer on assigning class toyota to car, the code i written below is working good.
#include <iostream>
using std::cout;
class Car
{
public:
Car(){cout << "A car";};
virtual void method1(){cout << "from car";};
};
class Toyota : public Car
{
public:
Toyota(){cout << "A toyota";};
void method1() {cout << "from toyota";};
};
class Lada : public Car
{
public:
Lada(){cout << "A Lada";};
void method1() {cout << "from lada";};
};
class User
{
public:
User(){cout << "A user";};
Car *car;
};
int main()
{
User *user = new User();
Toyota toyota;
user->car = &toyota;
delete user;
/***
if you dont need pointers then
User user;
Toyota toyota;
user.car = &toyota;
/**
}
I am having trouble finding the method to store instances of similar classes into a vector. I thought about using a base class, but I am not sure whether it will work. For example, using sports:
class player //base
{
std::string name;
int age;
player(std::string name, int age) name (name), age (age);
};
class soccerplayer: public player
{
float goal_per_game;
//etc
};
class basketballplayer: public player
{
float defensive_blocks;
float three_pointers_per_game;
//etc
};
class hockeyplayer: public player
{
//etc
};
std::vector<player> favoriteplayers;
favoriteplayers.push_back(player("Lionel Messi", 33));
I am not sure if there is a method to store the various instances of this class. If not, what workaround is possible?
You can use a vector of (smart) pointers to the base class vs. a vector of values.
std::vector<std::unique_ptr<player> > favoriteplayers;
favoriteplayers.emplace_back(new sockerplayer(...));
favoriteplayers.emplace_back(new hockeyplayer(...));
All items in the vector point to the player base-class, but they can actually be objects of derived classes.
I've been having trouble accessing the "getDegreeProgram()" method in my objects that are set to my array of pointers; all of my baseclass methods are working, but for some reason, my subclass methods aren't even visible. I'm suspecting that I don't have the syntax right, and its converting all of my subclass objects to the baseclass of student.
roster.h:
class roster {
private:
student** classRosterArray; //array of pointers
roster.cpp function that creates my objects and sets them to the array of pointers
void roster::createStudentObject() {
classRosterArray = new student *[5]; //array of pointers
if (degreeProgramInput == "NETWORK") {
classRosterArray[rosterCounter] = new networkStudent();
}
else if (degreeProgramInput == "SECURITY") {
classRosterArray[rosterCounter] = new securityStudent();
}
else classRosterArray[rosterCounter] = new softwareStudent();
}
student.h subclasses in question (they're subclasses of my baseclass "student")
class networkStudent:public student {
private:
int networkDegree;
public:
int getDegreeProgram();
networkStudent();
};
class securityStudent:public student {
private:
int securityDegree;
public:
int getDegreeProgram();
securityStudent();
};
class softwareStudent:public student {
private:
int softwareDegree;
public:
int getDegreeProgram();
softwareStudent();
};
As far as I understood, you are trying to access the elements of classRosterArray and trying to call getDegreeProgram().
For this problem, Make the getDegreeProgram() virtual function.
student.h
class student {
...
public:
virtual int getDegreeProgram() = 0; // pure virtual function
};
Subclasses of student
class networkStudent:public student {
private:
int networkDegree;
public:
virtual int getDegreeProgram();
networkStudent();
};
class securityStudent:public student {
private:
int securityDegree;
public:
virtual int getDegreeProgram();
securityStudent();
};
class softwareStudent:public student {
private:
int softwareDegree;
public:
virtual int getDegreeProgram();
softwareStudent();
};
Suggestion:
In this case, Because getDegreeProgram() seems to be a getter function, I think you should declare it as a const function.
Edit:
As rightly said by Richard, In C++ 11, override keyword was introduced for this purpose for the sub classes. So, instead of writing virtual int getDegreeProgram();, you could write int getDegreeProgram() override; also.
There are two you ways you can go about it.
Runtime Polymorphism - This method will require less code refactoring but at the cost of runtime. Each instance of a polymorphic class will have a pointer(vptr) to a table(vtable) of pointers to the different versions of the virtual function. This table will be used for finding the right version of the virtual function at runtime.
You can achieve runtime polymorphism here by making the getDegreeProgram function virtual in base class ie., Student and override it in derived classes ie., securityStudent, networkStudent and softwareStudent.
class Student {
...
public:
virtual int getDegreeProgram() = 0; // notice the virtual keyword and 0 at the end.
// 0 is for saying that it is pure virtual, meaning
// we don't have any definition for this function in
// this class. Such a class is also called as
// abstract class
...
}
class securityStudent : Student {
...
public:
int getDegreeProgram() override
{
// do the stuff you want to do
}
...
}
// driver stub
...
Student *student;
securityStudent sStudent;
networkStudent nStudent;
.
.
student = &sStudent;
student->getDegreeProgram(); // calls security student implementation of getDegreeProgram
student = &nStudent;
student->getDegreeProgram(); // calls network student implementation of getDegreeProgram
...
Static Polymorphism or CRTP or Simulated Dynamic Binding - This method does the same thing as above but with the advantage of knowing the type at compile time by means of some casting magic (below). Even this approach has its limitation like kludgy syntax and some amount of refactoring which is a lot more than in the 1st case and lack of readability due to terseness of templates etc.
The trick here is to get the derived class' information at compile time and typecast the this pointer of the base class to that of the derived class. :-)
template <typename StudentType>
class Student {
...
public:
int getDegreeProgram()
{
return (static_cast<StudentType*>(this))->getDegreeProgramImpl();
}
...
}
class securityStudent : public Student<securityStudent> {
...
public:
int getDegreeProgramImpl()
{
// write your specifc implementation here
}
...
}
// driver stub
...
securityStudent sStudent;
networkStudent nStudent;
.
.
sStudent.getDegreeProgram(); // calls security student implementation of getDegreeProgram
nStudent.getDegreeProgram(); // calls network student implementation of getDegreeProgram
...
I have a class "Player". Its members are simple strings and ints and I've got Getters and Setters for each of these...basic stuff: (there's a load of members so I've just given 3 to shrink the code):
PLAYER.H
class Player
{
private:
string Name;
string Role;
int FFDefence;
......etc
public:
//constructor function
Player(
string Name = "Not Stated",
string vRole = "Not Stated",
int vFFDefence = 0,
......etc
)
//Getter Functions
string GetName() const;
string GetRole() const;
int GetFFDefence() const;
.....etc
//Setter Functions
void SetName (string x);
void SetRole(string x);
void SetFFDefence(int x);
......etc
};
PLAYER.CPP
Player::Player( string vName,
string vRole,
int vFFDefence,
......etc
{
Name = vName;
Role = vRole;
FFDefence = vFFDefence,
......etc
}
//getter functions
string Player::GetName() const {return Name; };
string Player::GetRole() const {return Role; };
int Player::GetFFDefence() const {return FFDefence; };
.....etc
//Setter Functions
void Player::SetName(string x) { Name = x ; };
void Player::SetRole(string x) { Role = x ; };
void Player::SetFFDefence(int x) { FFDefence = x ; };
......etc
So yeah - pretty bog standard......now I have a second class where one of the member functions is a Player Class itself.
BATTER.H
class Batter
{
private:
Player ID;
int Touch;
....etc
public:
Batter(Player vID, int vTouch = 0....etc);
//Getter Functions
string GetRole() const;
int GetFFDefence() const;
int GetBFDefence() const;....and so on.
OK - that's the code out of the way!!!!
So I've got it doing everything I want in terms of passing variables in and out....so I can create
Player Dave ("Dave", "Opener", 98, ....etc)
then later on (when I need it) create
Batter OnStrike (Dave, 10, .....etc)
All gravy....OK so I've started looking into inheritance and realized this is what I should be doing....back converting not a problem (did this with arrays and vectors the other day)...
Here's my problem:
With what I've got now, I can create "Player Dave" and then pass him into the subclass of Batter whenever I need to. How do I do the same with traditional inheritance? How do I take a specific instance (already created) of Player and use that as the parent for a specific instance of the child class Batter? As far as I can deduce at the moment, you need to create both at the same time.
Just initialize your base object with the object provided:
class Player
{
Player(Player const&); // copy constructor (might be implicitly generated)
...
};
class Batter:
public Player
{
Batter(Player const& p, other arguments):
Player(p),
...
{
...
}
};
On the other hand, there's the question whether inheritance of Batter from Player is the right tool in your case. The fact that you pass a Player object to construction hints at the fact that a Player may become a batter, and maybe later also stop being a batter. That is, Batter is actually a role which the player may temporarily have. Therefore it may be a better idea to separate the Player object from the role, by having a separate Role hierarchy where Batter and Pitcher derive from Role, and Player has a method which returns the current role, and another which can assign another role to the player.
The idea with polymorphism is that if you have some class:
class Batter : public Player
Then every batter is also a player. So, for example, if you had a batter called dave, you'd be able to use dave wherever a Player was expected. You could for example:
int FunctionThatDoesSomething(Player &p, string some_parameter, ...);
...
FunctionThatDoesSomething(dave, "foo", ...);
Be careful to avoid slicing, which is when you accidentally make a base class copy of a subclass (this does not preserve subclass specific state. If you need to pass dave around, make sure you only refer to dave, don't copy dave. dave doesn't like to be copied.)
How exactly you build your players and batters is up to you. For example, your might have constructors with these signatures:
Player::Player(string name, string role, int vFFDefense);
Batter::Batter(Player &p, int vTouch, int moreStats);
Under some circumstances this might be convenient, but it's not particularly efficient because you have to create and copy the base class (not that efficiency is a big deal for small classes like this, but there's no point in trying to do things the dumb way). You would be better off making a constructor that takes everything it needs, and uses subobject initialization:
Batter::Batter(string name, string role, int vFFDefense, int moreBaseStats, int vTouch, int moreStats) : Player(name, role, vFFDefense, moreBaseStats)
{
...
But your implementation is ultimately up to you.
You are doing aggregation here, not inheritance. A Batter has a player. Inheritance would be a batter is a player.
Your design is good, you don't want to do inheritance for this.
While it's okay to say a Batter is always a Player from a conceptual point of view in this case, when you are dealing with a Batter, much of what player describes is irrelevant and when dealing with them as a player, they may not be batting.
Baseball is a bit foreign to me, but if you went down the inheritance route, you'd have descendants of player for each role in the team and get in a right mess when your pitcher came out to bat.
A classic illustration of the inheritance route.
Is
Animal -> Fliers -> Bird -> Merlin
-> Runners -> Rodent -> Gerbil
Where do you put Bat and Ostrich?
You are left with saying a Bat is a bird, inventing a new class FlyingRodent, or Rodent having two parents...
All of which will lead to a confusing bug fest.
View all unconscious reaches for the inheritance hammer with extreme suspicion.
It really depends how you actually want your code factored.
Will a given Player ever become anything other than a Batter? If they can, then it is probably best to use aggregation (in a similar way to how you do now).
If you are aggregating then maybe use another class to hold the data. You could have a PlayerInfo class or struct and aggregate that:
struct PlayerInfo
{
string role_;
int ff_defence_;
...
};
class Player
{
public:
Player(PlayerInfo const& info)
: info_(info)
{}
virtual ~Player() = 0;
virtual void doSomething();
PlayerInfo const& getPlayerInfo() const { return info_; }
private:
PlayerInfo info_;
};
class Batter : public Player
{
public:
Batter(PlayerInfo const& info)
: Player(info)
{}
virtual void doSomething();
};
If you actually want the inheritance then other answers here tell you what you need to do - construct an instance of Batter and pass on the constructor arguments to a constructor of the class you derive from (e.g. Batter) to initialize it.
Think carefully about what are you trying to express in your code.
The reason you would want to have Batter derived from Player is if you need virtual functions in Player that are implemented in Batter and do something different depending upon whether or not it is a Player or a Batter.
As an aside, its best to keep base classes abstract if possible, so Player would never be instantiated directly and would always need to be derived. I'd recommend reading Scott Meyers 'More Effective C++' to understand why this is. There's a section in there devoted to that. In fact some of the finer points of inheritance and OO design in general are nicely explained.
What you may actually want is something slightly different depending upon where you anticipate your model to change, and additionally where you you need it to have the dynamic behaviour possible through the use of virtual functions?
You could have a Player class that has all your player specific details. Then you could have a PlayerBehaviour class that implements what the player does:
class Player;
class PlayerBehaviour
{
public:
virtual ~PlayerBehaviour() = 0;
virtual void doSomething(Player* player) = 0;
};
inline PlayerBehaviour::~PlayerBehaviour() {}
class BatterBehaviour : public PlayerBehaviour
{
public:
virtual void doSomething(Player* player) {
if (player->isAngry()) {
throwBatOnFloor();
}
}
void throwBatOnFloor();
};
class Player {
public:
Player(...stuff...);
void doSomething() {
if (behaviour_.get()) {
behaviour_->doSomething(this);
}
}
private:
auto_ptr<PlayerBehaviour> behaviour_;
// Due to the auto_ptr, the default copy and assignment operators are
// dangerous. You could use a smart pointer or implement
// these by having a clone() function in the behaviour class.
// Therefore copy/assign are private to prevent accidental misuse.
Player(Player const&);
Player& operator=(Player const&);
};
So, inheriting Batter from Player models the situation as a Batter is-a Player.
Having a Behaviour models the situation as a Player has-a Behaviour such as a Batter.
Stop using the "parent" and "child" terminology, think of "base" classes and "derived" classes ... that's what everyone else calls them. "Parent" and "child" can be used in too many other ways (e.g. an object that owns another one) so it's confusing terminology if you're talking about an inheritance relationship.
The derived class contains an entire instance of the base type inside itself. When the derived constructor starts executing the first thing it does is construct all its bases, which it does by calling their constructors. So the derived class can control how the base is constructed by passing it the right arguments:
class Base {
public:
Base(std::string nm) : name(nm) { }
protected:
std::string name;
};
class Derived : public Base {
public:
// construct my base by passing name to it
Derived(std::string name, int ii) : Base(name), i(ii) { }
private:
int i;
};
Derived d("Dave Derived", 1);
This creates both the Base and Derived objects at the same time (one inside the other) which is probably what you want.
If do have an existing Base object and you want the base part of the derived object to be the same as that other one then you can pass it an object to copy:
class Base {
public:
Base(std::string nm) : name(nm) { }
protected:
std::string name;
};
class Derived : public Base {
public:
// construct my base by passing name to it
Derived(std::string name, int ii) : Base(name), i(ii) { }
// construct my base by passing another Base to it:
Derived(const Base& b, int ii) : Base(b), i(ii) { }
private:
int i;
};
Base b("Barry Base");
Derived d(b, 2);
This doesn't put the existing Base object, b, inside the Derived one, instead it makes the base object a copy of the object b, by calling the Base copy constructor, so now there are two Base objects, the original b and the one inside d. This is closer to your original code, where the Batter contains a Player member, but now it's a base class not a member.
If you do want to use inheritance, the first form is probably more appropriate, where you pass arguments to the derived class and it uses those arguments to create the base.
in C++;
Is there a way of calling a function from a derived class through the base class
even when the function is not overridden? In other words, I'm using a base class in
order to have heterogeneous containers without boost; I want to call a member function
that is only specific to a derived class...
Example:
(I just made this code up so there's probably a syntax error but hopefully you get the gist)
class Vehicle
{
public:
virtual void do_vehicle_stuff();
// virtual void do_car_specific_stuff(); makes no sense here
}
class Car : public Vehicle
{
public:
void do_vehicle_stuff();
void do_car_specific_stuff();
}
Car a,b;
list<Vehicle> vehicle_list;
vehicle_list.push_back(a);
vehicle_list.push_back(b);
vehicle_list.front().do_car_specific_stuff();
error: 'Class Vehicle' has no member named 'do_car_specific_stuff()'
You are slicing your classes when you insert them into the list. In
C++ subtype polymorphism (the kind of polymorphism you are using) only
works through references or pointers but not values. When you insert
your carS into the list they are converted to VehicleS.
An example:
Car c;
std::vector<Vehicle> vs;
vs.push_back(c); // slicing happens
vs.front(); // not a car anymore, but just a vehicle,
// the Car-ness is lost through the copy operation
How do to it:
std::vector<std::unique_ptr<Vehicle>> vs;
vs.push_back(new Car());
vs.front(); // actually a Car
After you have resolved that fundamental flaw of your code, this might
help you:
Vehicle* vehiclep = new Car();
if(auto carp = dynamic_cast<Car*>(vehiclep)) {
carp->do_car_specific_stuff();
}
This is a rather costly operation and usually an indication of a
design smell, so you might want to rethink what you are doing.
Here's a more appropriate design:
struct Vehicle
{
virtual ~Vehicle() { }
void do_vehicle_stuff()
{
vehicle_impl();
}
private:
virtual void vehicle_impl() = 0;
};
struct Car : Vehicle
{
private:
virtual void vehicle_impl()
{
my_vehicle_stuff();
my_car_specific_stuff();
}
void my_vehicle_stuff() { /* what you had originally */ }
void my_car_specific_stuff() { /* car-only stuff */ }
};
std::list<std::unique_ptr<Vehicle>> vehicles;
vehicles.emplace_back(new Car);
vehicles.emplace_back(new Motorcycle);
vehicles.emplace_back(new Carriage);