I'm trying to understand virtual classes in C++. In Wikipedia, I found this example:
#include <iostream>
class Machine {
public:
void run() { }
class Parts {
public:
virtual int get_wheels() = 0;
virtual std::string get_fuel_type() = 0;
};
};
// The inner class "Parts" of the class "Machine" may return the number of wheels the machine has.
class Car: Machine {
public:
void run() {
std::cout << "The car is running." << std::endl;
}
class Parts: Machine::Parts {
public:
int get_wheels() override {
std::cout << "A car has 4 wheels." << std::endl;
return 4;
}
std::string get_fuel_type() override {
std::cout << "A car uses gasoline for fuel." << std::endl;
return "gasoline";
}
};
};
I can get the number of wheels of a car with:
Car::Parts c_p;
c_p.get_wheels();
Is there any other (simple) way? Is there any way instantiating only Car car ?
Update:
I understand the concerns, but I find it useful as a nested interface (with minimal changes):
#include <iostream>
#include <memory>
class Machine {
public:
virtual void run() = 0;
class Parts {
public:
virtual int get_wheels() = 0;
virtual std::string get_fuel_type() = 0;
};
};
class Car: public Machine {
public:
void run() {
std::cout << "The car is running." << std::endl;
}
class Parts: public Machine::Parts {
public:
int get_wheels() override {
std::cout << "A car has 4 wheels." << std::endl;
return 4;
}
std::string get_fuel_type() override {
std::cout << "A car uses gasoline for fuel." << std::endl;
return "gasoline";
}
};
};
int main () {
std::shared_ptr<Machine> X = std::make_shared<Car>();
(*X).run();
std::shared_ptr<Machine::Parts> Y = std::make_shared<Car::Parts>();
(*Y).get_wheels();
return 0;
}
I don't find any other code with this functionality. The only thing I miss is the possibility to access get_wheels directly from X. For instance, let's consider that I have a Machine in my program. The kind of machine I have will be specified dynamically. I want to know the number of wheels of this machine, but the method get_wheels must be inside a nested class Parts. The closer to solve this problem that I've got is with the code above, which gives me Machine and Machine::Parts as interfaces.
A simple solution would be to have a member part of you car:
struct Car : Machine {
struct Parts : Machine::Parts {
int get_wheels() override {
std::cout << "A car has 4 wheels." << std::endl;
return 4;
}
std::string get_fuel_type() override {
std::cout << "A car uses gasoline for fuel." << std::endl;
return "gasoline";
}
} parts; // <---
// or declare it as a separated member:
// Parts parts;
};
That way, you can call member functions like this:
Car car;
std::cout << car.parts.get_weels();
No. As it stands, a Car instance does not have any Car::Parts instances, nor any method that returns one.
The text around the example seems to be assuming that there is an instance of Machine::Parts associated with Machine somehow, which magically becomes a Car::Parts in Car. This may be the case in some other language, but it is not the case in C++.
A much more idomatic design would be to have a traits class template that Machine subclasses specialise.
template <typename Machine>
struct MachineParts;
template <>
struct MachineParts<Car> {
static int get_wheels() {
std::cout << "A car has 4 wheels." << std::endl;
return 4;
}
static std::string get_fuel_type() {
std::cout << "A car uses gasoline for fuel." << std::endl;
return "gasoline";
}
};
template <>
struct MachineParts<Bicycle> {
static int get_wheels() {
std::cout << "A bike has 2 wheels." << std::endl;
return 2;
}
static std::string get_fuel_type() {
std::cout << "A bike uses muscles for fuel." << std::endl;
return "muscles";
}
};
Related
Based on the comments to my last question (Getter-function for derived class in derived class, when using pointer to base class), I've been told that I have to use static_cast when recasting my pointer from the base class to the derived class, in order to access the derived class. I tested that using the following code:
#include <iostream>
class class_data{
public:
int val_a = 0;
double val_b = 0.;
};
class overridden_class_data : public class_data{
public:
int val_c = 0.;
};
class overridden_class_data_II : public class_data{
public:
int val_c = 12.;
};
class BaseClass{
public:
BaseClass(){};
virtual void print_data() = 0;
virtual class_data *get_local_data() = 0;
class_data local_class_data;
};
class DerivedClass : public BaseClass{
public:
DerivedClass(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
local_class_data.val_c = 14;
};
void print_data() override{
std::cout << "Hello World\n";
}
class_data * get_local_data() override {
return &local_class_data;
}
overridden_class_data local_class_data;
};
class DerivedClassII : public BaseClass{
public:
DerivedClassII(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
};
void print_data() override{
std::cout << "Hello World\n";
}
class_data * get_local_data() override {
return &local_class_data;
}
overridden_class_data_II local_class_data;
};
void test_func(BaseClass *class_pointer){
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << class_pointer->local_class_data.val_a << '\n';
class_pointer->local_class_data.val_a = 5;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
class_pointer->get_local_data()->val_a = 15;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << static_cast<overridden_class_data*>(class_pointer->get_local_data())->val_c << '\n';
}
int main(void){
std::cout << "From main\n";
DerivedClass DClass;
DerivedClassII EClass;
std::cout << "DClass: \n";
test_func(&DClass);
std::cout << "EClass: \n";
test_func(&EClass);
return 0;
}
Here I have two derived classes, which use two different derived classes as class variable. To access the data of those classes I have to use static_cast onto the returned base-class pointer to cast it back to the derived class. Still, I do not want to rewrite the function test_func() for both classes, but instead use the same function for them.
Initially, I thought that I had to write the last line of the function twice, recasting the class variable pointer once to overridden_class_data* and once to overridden_class_data_II*, depending on the input class. But after testing I noticed that I do not have to do that, I can recast it to overridden_class_data*, but it still acts as if I recasted it overridden_class_data_II*. Why? Is it because both classes contain the same elements, and therefore the pointer can point to the same spot?
As for your original question, yes this is happening just because (1) the data members of your class are identically setup and (2) static_cast is not safe for such polymorphic casts.
A simple counterexample to break test_func would be(code):
class overridden_class_data : public class_data{
public:
int val_pad = 0.;
int val_c = 23.;
};
which would incorrectly then print the value 0 instead of 12 for the EClass pointer->get_local_data()->val_c.
A few ways you could go about solving this(making test_fn single use):
Correctly detect the above issue using dynamic_casts, but then test_func would need to be called with appropriate explicit template args.
Forego the casts with compile time safety by making a simple generic test_func and using covariant return types. You mentioned that your concerned about too many templates - Is it code bloat you are worried about?
#churill suggestion of using a virtual getter like get_val_c.
Here is the snippet for the 2nd method suggested - I've marked the changes I made(code):
#include <iostream>
class class_data{
public:
int val_a = 0;
double val_b = 0.;
};
class overridden_class_data : public class_data{
public:
int val_pad = 23;
int val_c = 0.;
};
class overridden_class_data_II : public class_data{
public:
int val_c = 12.;
};
class BaseClass{
public:
BaseClass(){};
virtual void print_data() = 0;
virtual class_data *get_local_data() = 0;
class_data local_class_data;
};
class DerivedClass : public BaseClass{
public:
DerivedClass(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
local_class_data.val_c = 14;
};
void print_data() override{
std::cout << "Hello World\n";
}
// use covariant return type
overridden_class_data * get_local_data() override {
return &local_class_data;
}
overridden_class_data local_class_data;
};
class DerivedClassII : public BaseClass{
public:
DerivedClassII(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
};
void print_data() override{
std::cout << "Hello World\n";
}
// use covariant return type
overridden_class_data_II * get_local_data() override {
return &local_class_data;
}
overridden_class_data_II local_class_data;
};
template <typename T>
void test_func(T *class_pointer){ // make generic
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << class_pointer->local_class_data.val_a << '\n';
class_pointer->local_class_data.val_a = 5;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
class_pointer->get_local_data()->val_a = 15;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << class_pointer->get_local_data()->val_c << '\n';
}
int main(void){
std::cout << "From main\n";
DerivedClass DClass;
DerivedClassII EClass;
std::cout << "DClass: \n";
test_func(&DClass);
std::cout << "EClass: \n";
test_func(&EClass);
return 0;
}
I got this:
class Core
{
protected:
static unsigned int id_seed;
unsigned int id;
std::string status;
public:
friend class CPU;
Core();
~Core();
virtual void procesare(std::string aplicatie) = 0;
};
class CoreScreen: public Core
{
public:
CoreScreen();
~CoreScreen();
void procesare(std::string aplicatie);
};
and corescreen.cpp:
#include "CoreScreen.h"
CoreScreen::CoreScreen()
{
}
CoreScreen::~CoreScreen()
{
}
void CoreScreen::procesare(std::string aplicatie)
{
std::string buffer;
std::ifstream file_in(aplicatie);
if (file_in.is_open()) {
std::cout << "Aplicatia " << aplicatie << " ruleaza: " << std::endl;
while (getline(file_in, buffer)) {
std::cout << buffer;
}
file_in.close();
}
else {
throw new CExceptie(APP_FAIL, " Aplicatia nu a putut rula!");
}
}
When I use in main:
CoreScreen CS1, CS2, CS3, CS4;
I get this error: 'Core' cannot instantiate abstract class.
What's the problem? I thought I have my virtual function declared in CoreScreen correctly.
As I presume you know, "Core" is an abstract class, by virtue of the fact it has a pure virtual function: virtual void procesare(std::string aplicatie) = 0;.
I presume you also know that you can't instantiate an abstract class: hence your error.
The question is:
Why does the compiler think you're trying to instantiate an instance of "Core"?
Are you?
It looks like you're trying to instantiate four CoreScreen objects: CoreScreen CS1, CS2, CS3, CS4;. If so, that should be perfectly OK.
You're correct: procesare() is virtual ("pure virtual", as it happens). You've indeed overridden it correctly in CoreScreen.cpp: it DOESN'T look like that's the problem.
Q: Did you ever implement Core::Core() and Core::~Core() anywhere? If not, how did you even compile?
Q: Are you SURE you're not trying to create an instance of "Core" anywhere (even "accidentally")?
For whatever it's worth, the following MCVE compiles and runs fine (Ubuntu 18, GCC 7.3.0):
TestCore.h:
/*
* TestCore.h
*/
#ifndef TESTCORE_H_
#define TESTCORE_H_
#include <string>
class Core
{
protected:
static unsigned int id_seed;
unsigned int id;
std::string status;
public:
friend class CPU;
Core();
~Core();
virtual void procesare(std::string aplicatie) = 0;
};
class CoreScreen: public Core
{
public:
CoreScreen();
~CoreScreen();
void procesare(std::string aplicatie);
};
#endif /* TESTCORE_H_ */
TestCore.cpp:
/*
* TestCore.cpp
*/
#include <iostream>
#include <fstream>
#include "TestCore.h"
Core::Core()
{
std::cout << "Core::Core()..." << std::endl;
}
Core::~Core()
{
std::cout << "Core::~Core()..." << std::endl;
}
CoreScreen::CoreScreen()
{
std::cout << "CoreScreen::CoreScreen()..." << std::endl;
}
CoreScreen::~CoreScreen()
{
std::cout << "CoreScreen::~CoreScreen()..." << std::endl;
}
void CoreScreen::procesare(std::string aplicatie)
{
std::cout << "CoreScreen::procesare(" << aplicatie << ")" << std::endl;;
}
int main () {
std::cout << ">>main()..." << std::endl;
CoreScreen CS1, CS2, CS3, CS4;
CS1.procesare("Testing CS1");
std::cout << "<<main()." << std::endl;
return 0;
}
SAMPLE OUTPUT:
>>main()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
CoreScreen::procesare(Testing CS1)
<<main().
You'll note that I implemented Core::Core() and Core::~Core(). If you don't need them - then don't even put them in your .h class definition.
'Hope that helps
I'm working with my code and I faced this problem. I want to put 3 different classes data in single vector, so I created base class vector. It look like this :
std::vector <Video*> vid_list;
When I read the file I push data in this vector using one of the derived class constructors like that :
vid_list.push_back(new Official_Music_Video(video_title, video_time,
Date(y,m,d), num_of_views));
so I want to display this data on the screen, but my base class only got methods for
std::string title;
double time;
Date date_of_release;
but not for int number_of_views. I heard that if I wanna use derived class getter method I have to use upcasting so I tried to make this
void views (Video& v) {
v.get_views();
}
and then in my display method
void Official_Music_Video::display_info(std::vector <Video*>& vid_list){
Official_Music_Video ofc;
for (unsigned int i = 0; i < vid_list.size(); i++){
cout << vid_list[i]->get_title() << " " << vid_list[i]->get_time()
<< " " << vid_list[i]->write_year_to_file() << "-" <<
vid_list[i]->write_month_to_file() << "-" << vid_list[i]-
>write_day_to_file () << endl;
cout << "This video viewed " << vid_list[i].views(ofc) << " times"
<< endl;
}
}
But it's not working. Can you help me understand where I made mistake and what's wrong ?
If all three of your derived classes have a "number_of_views" method, put it in the base class as well, and problem solved. If not, then your code is nonsensical. What do you expect to happen when you put an "Unofficial_Music_Video" into the vector, and run your loop over it?
If you really need to add per-type behavior to the class, consider what you actually want to accomplish. Do you need users of Video to be able to query "number_of_views", despite the fact that field doesn't exist for all subtypes? Maybe you just want to access a human-readable description of the statistics? If that's the case, it might make the most sense to add a "virtual std::string StatsSummary()" method to Video, and make subclasses implement it as required.
You might want to move some of the implementation to the base class or so, but this is something that could help you finding the solution:
#include <vector>
#include <string>
#include <iostream>
class Date // for demo only
{
public:
Date(int y, int, int m, int d)
: y(y) , m(m), d(d) {}
int y;
int m;
int d;
};
class Video
{
public:
virtual std::string get_title() = 0;
virtual int get_time() = 0;
virtual int write_year_to_file() = 0;
virtual int write_month_to_file() = 0;
virtual int write_day_to_file () = 0;
virtual ~Video(){}
virtual void display_info()
{
std::cout << get_title()
<< " " << get_time()
<< " " << write_year_to_file()
<< "-" << write_month_to_file()
<< "-" << write_day_to_file ()
<< std::endl;
}
};
class VideoWithViewCount
: public Video
{
public:
virtual int views() = 0;
virtual void display_info()
{
Video::display_info();
std::cout << "This video viewed " << views() << " times" << std::endl;
}
};
class Official_Music_Video : public VideoWithViewCount
{
public:
Official_Music_Video(std::string _video_title, int _video_time, Date _date, int _Num_of_views)
: d(_date)
, time(_video_time)
, Num_of_views(_Num_of_views)
, video_title(_video_title)
{}
virtual int get_time() override {return time; };
virtual int write_year_to_file() override { return d.y; } // better call them get...
virtual int write_month_to_file() override {return d.m; }
virtual int write_day_to_file () override { return d.d; }
virtual int views() override {return Num_of_views; };
private:
Date d;
int time;
int Num_of_views;
std::string video_title;
};
class Other_Video : public Video
{
public:
Other_Video(std::string _video_title, int _video_time, Date _date)
: d(_date)
, time(_video_time)
, video_title(_video_title)
{}
virtual int get_time() override {return time; };
virtual int write_year_to_file() override { return d.y; }
virtual int write_month_to_file() override {return d.m; }
virtual int write_day_to_file () override { return d.d; }
private:
Date d;
int time;
std::string video_title;
};
int main(int,char**)
{
std::vector <Video*> vid_list;
// could also use unique_ptr or shared_ptr from #include <memory> in vector as follows:
// std::vector <unique_ptr<Video> > vid_list;
// std::vector <shared_ptr<Video> > vid_list;
// fill video vector
// vid_list.push_back(new Official_Music_Video(video_title, video_time, Date(y,m,d), num_of_views));
for (auto v : vid_list) // when using unique_ptr remember to use "const auto&" instead of "auto"
{
v->display_info();
}
return 0;
}
I am working on an assignment using sub classes demonstrating polymorphism. This program requires a name to be given for each of the new objects. I am only supposed to have string getName(){return name;} (this is located in the base class). There is also a constructor in each of the classes class(string){}. In the main function I want to set the name for each of the objects. Any advice is much appreciated in how I should do so!
h file:
#ifndef DUCK_H
#define DUCK_H
#include <string>
using namespace std;
class Duck
{
private:
string name;
public:
Duck(){}
Duck(string){}
string getName() { return name; };
virtual string quack() {return "Which"; }
virtual string fly() { return "How?"; }
};
class RubberDuck : public Duck
{
public:
RubberDuck(){}
RubberDuck(string) {}
string quack() { return "Squeak"; }
string fly() { return "Fly with bounce"; }
};
class MallardDuck : public Duck
{
public:
MallardDuck(){}
MallardDuck(string) {}
string quack() { return "Quack"; }
string fly() { return "Fly with wings"; }
};
class RocketDuck : public Duck
{
public:
RocketDuck(){}
RocketDuck(string) {}
string quack() { return "Zoom"; }
string fly() { return "Fly with rockets"; }
};
#endif // !1
cpp file:
#include <iostream>
#include "Duck.h"
using namespace std;
//void display(Duck *d);
int main()
{
Duck d1;
MallardDuck md;
RubberDuck rbd;
RocketDuck rd;
//for main duck
//Duck duck("Donald");
//cout << duck.getName();
cout << d1.quack() <<"\n";
cout << d1.fly() <<"\n";
cout << "\n";
//for rubber duck
RubberDuck rbdname("Rubby");
cout << rbd.quack() << "\n";
cout << rbd.fly() << "\n";
cout << "\n";
//for mallard duck
MallardDuck mdname("Mally");
cout << md.quack() << "\n";
cout << md.fly() << "\n";
cout << "\n";
// for rocket duck
RocketDuck rdname("Rocky");
cout << rd.quack() << "\n";
cout << rd.fly() << "\n";
cout << "\n";
//polymorphism
Duck *d2 = new MallardDuck();
cout << d2->getName() << "\n";
cout << d2->quack() << "\n";
cout << d2->fly() << "\n";
cout << "\n";
return 0;
}
/*void display(Duck d)
{
cout << d.quack();
}
*/
Are you asking how to call the constructor you've defined? You would do that like
Duck duck("Drake Mallard");
With this code:
Duck(){}
Duck(string){}
You don't initialize your member name, whether you call the default constructor or the string one.
You have to use the input parameter like I showed you:
Duck(string const & input_name) : name(input_name) {}
^^^^^^^^^^^^^^^^
The underlined part initializes your member name to the value "Drake Mallard" when you do:
Duck duck("Drake Mallard");
Then, you will have duck.getName() returning "Drake Mallard".
And you have to apply the same principle in your derived classes, to call this very same base constructor:
class RubberDuck : public Duck
{
public:
RubberDuck() : Duck("RubberDuck") {}
RubberDuck(string const & input_name) : Duck(input_name) {}
Then
RubberDuck rubber; // name = "RubberDuck"
RubberDuck rubber("Ruber"); // name = "Rubber"
But also:
RubberDuck * rubber = new RubberDuck(); // name = "RubberDuck"
RubberDuck * rubber = new RubberDuck("Ruber"); // name = "Rubber"
If you ask, the front part Duck:: in my comment considered you where implementing your constructor outside of class Duck { ... };.
You should avoid using namespace, especially within headers.
I stumbled across this piece of code when I researched for a good example for Observer Design pattern. In main, it gets error, taking address of temporary[-fpermissive] which I dont dont understand what it is frankly. Sending a class refference to an function? Is this real life?
#include <vector>
#include <iostream>
using namespace std;
class AlarmListener
{
public:
virtual void alarm() = 0;
};
class SensorSystem
{
vector < AlarmListener * > listeners;
public:
void attach(AlarmListener *al)
{
listeners.push_back(al);
}
void soundTheAlarm()
{
for (int i = 0; i < listeners.size(); i++)
listeners[i]->alarm();
}
};
class Lighting: public AlarmListener
{
public:
/*virtual*/void alarm()
{
cout << "lights up" << '\n';
}
};
class Gates: public AlarmListener
{
public:
/*virtual*/void alarm()
{
cout << "gates close" << '\n';
}
};
class CheckList
{
virtual void localize()
{
cout << " establish a perimeter" << '\n';
}
virtual void isolate()
{
cout << " isolate the grid" << '\n';
}
virtual void identify()
{
cout << " identify the source" << '\n';
}
public:
void byTheNumbers()
{
// Template Method design pattern
localize();
isolate();
identify();
}
};
// class inheri. // type inheritance
class Surveillance: public CheckList, public AlarmListener
{
/*virtual*/void isolate()
{
cout << " train the cameras" << '\n';
}
public:
/*virtual*/void alarm()
{
cout << "Surveillance - by the numbers:" << '\n';
byTheNumbers();
}
};
int main()
{
SensorSystem ss;
ss.attach(&Gates());
ss.attach(&Lighting());
ss.attach(&Surveillance());
ss.soundTheAlarm();
}
This is ill-formed:
ss.attach(&Gates());
^^^
Gates() is an rvalue (specifically, a prvalue). You cannot take the address of an rvalue. It's not an object that has identity, so it doesn't really have an address that you can take. The language is preventing you from doing something that doesn't make sense to do. If you did store a pointer to this temporary, you'd just end up with a dangling pointer since at the end of this line the temporary Gates would be destroyed.
Since SensorSystem doesn't own its AlarmListeners, you'll have to create them up front:
Gates gates;
Lighting lighting;
Surveillance surveillance;
SensorSystem ss;
ss.attach(&gates);
ss.attach(&lighting);
ss.attach(&surveillance);