How can i overload the operator << so it can show the attribute of the parent class as well when those attribute are private withing the parent class??
Parent Class:
Movie header
ifndef _Movie
#define _Movie
#include <string>
using namespace std;
Class Movie{
private:
string title;
int year;
float duration;
public:
Movie();
Movie(string, int, float);
Movie(const Movie&);
void Print();
};
#endif
Movie.cc
#include "Movie.h"
#include<iostream>
Movie::Movie(){
std::cout<< "Defaut Constructor" <<std::endl;
}
Movie::Movie(string t, int a, float d){
this->title = t;
this->year = a;
this->duration = d;
}
Movie::Movie(const Movie &M){
std::cout << "copy" << std::endl;
this->title = M.title;
this->year = M.year;
this->duration = M.duration;
void Movie::Print(){
std::cout << "Info" << std::endl;
std::cout << "------------------" << std::endl;
std::cout << "Title: " << title <<std::endl;
std::cout << "Year: " << year <<std::endl;
std::cout << "Duration: " << duration <<std::endl;
std::cout << "------------------" << std::endl;
if (duration>=60){
std::cout << "Long Movie" << std::endl;
}
else{
std::cout << "Short Movie" << std::endl;
}
}
Child Class:
Prize header:
#ifndef _Prize
#define _Prize
#include "Movie.h"
#include <iostream>
using namespace std;
class Prize : public Movie{
private :
int oscar;
bool por;
public:
Prize();
Prize(string, int, float, int, bool);
Prize(const Prize &);
friend ostream& operator<<(ostream& out,const Prize&f);
};
#endif
prize cc
#include "Prize.h"
#include<iostream>
Prize::Prize()
{
cout<<"Defaut Constructor Prize"<<endl;
}
Prize::Prize(string t, int a, float d, int c, bool p):Movie(t,a,d) //inherite t,a,d from the mother class
{
this->oscar = c;
this->por = p;
}
Prize::Prize(const Prize &f):Movie(f)
{
this->oscar = f.oscar;
this->por = f.por;
}
Here i need to show the attribute of the parent class
as well i can't really add Movie::Print()
and i can't do f.title because it's private within the Movie class
std::ostream& operator<<(std::ostream& out,const Prize& f){
// Movie::print;
// out << f.title << std:endl;
out << f.cesar <<std::endl;
out << f.por << std::endl;
return out;
}
My recommendation is that you instead make an operator<< function for the base class. This operator then calls a virtual "output" function to do the actual output.
Each child-class then overrides this output function to output its own data, and call the base-class output function to let it print its own data.
For your classes it could be something like this:
class Movie
{
private:
std::string title;
protected:
virtual std::ostream& output(std::ostream& out) const
{
return out << title;
}
public:
// Other public members...
friend std::ostream& operator<<(std::ostream& out, Movie const& movie)
{
return movie.output(out);
}
};
class Prize : public Movie
{
protected:
std::ostream& output(std::ostream& out) const override
{
return Movie::output(out) << ' ' << cesar << ' ' << por;
}
// Other public and private members...
};
Related
I was trying to learn operator overloading in C++ PL. I made an exercise shown below. What I want to do is overload << operator for each derived class and use it on my main. But whenever I do it, its only working for Base class. What is the problem here?
Class Employee:
class Employee {
public:
string name;
int id;
int exp_level;
double salary;
Employee() {
this->name = "";
this->id = 0;
this->exp_level = 0;
this->salary = 0.0;
}
~Employee() {
//WTF
}
virtual void calculateSalary() {
//CODE
}
virtual void registerX() {
//CODE
}
friend ostream& operator<<(ostream& os, const Employee& e) {
os << e.name << " " << e.exp_level << " " << e.id << " " << e.salary << endl;
return os;
}
};
Class Technical:
class Technical : public Employee {
public:
string profession;
Technical() {
this->profession = "";
}
~Technical() {
}
virtual void calculateSalary() {
//CODE
}
virtual void registerX() {
//CODE
}
friend ostream& operator<<(ostream& os, const Technical& e) {
os << e.name << " " << e.exp_level << " " << e.id << " " << e.salary << "Technical" << endl;
return os;
}
};
Class Engineer:
class Engineer : public Employee {
public:
Engineer() {
}
~Engineer() {
}
virtual void calculateSalary() {
//CODE
}
virtual void registerX() {
//CODE
}
friend ostream& operator<<(ostream& os, const Engineer& e) {
os << e.name << " " << e.exp_level << " " << e.id << " " << e.salary << "Engineer" << endl;
return os;
}
};
Main Method:
int main()
{
Employee* e = new Employee();
Employee* t = new Technical();
Employee* ee = new Engineer();
cout << *e << endl;
cout << *t << endl;
cout << *ee << endl;
}
Output:
0 0 0
0 0 0
0 0 0
C++ chooses the best overload based on the static type's of the function arguments, and because the type is Employee in this case, the Employee's operator<< gets called.
If you want it to call the correct version when you have a static type pointer / reference to it that doesn't match it's dynamic type you'll have to use a virtual function or use dynamic_casts / typeid to check for the concrete runtime type (virtual functions are the cleanest approach imho)
Example: godbolt
class Employee {
public:
virtual ~Employee() = default;
friend std::ostream& operator<<(std::ostream& os, const Employee& e) {
return e.put(os);
}
protected:
virtual std::ostream& put(std::ostream& os) const {
os << "Employee!";
return os;
}
};
class Technical : public Employee {
protected:
std::ostream& put(std::ostream& os) const override {
os << "Technical Employee!";
return os;
}
};
class Engineer : public Employee {
protected:
std::ostream& put(std::ostream& os) const override {
os << "Engineer Employee!";
return os;
}
};
int main() {
Employee* e = new Employee();
Employee* t = new Technical();
Employee* ee = new Engineer();
std::cout << *e << std::endl;
std::cout << *t << std::endl;
std::cout << *ee << std::endl;
delete ee;
delete t;
delete e;
}
would result in:
Employee!
Technical Employee!
Engineer Employee!
Also keep in mind that once you have at least 1 virtual function in a class then the destructor should almost definitely be also virtual.
e.g.:
Employee* e = new Technical();
delete e;
would only call ~Employee(), but not ~Technical(), if the destructor is not virtual.
So whenever you want to delete an object through a pointer to one of it's base-classes the destructor needs to be virtual, otherwise it's undefined behavior.
Due to these declarations
Employee* e = new Employee();
Employee* t = new Technical();
Employee* ee = new Engineer();
the static type of the expressions *e, *t, *ee is Employee &. So the operator
friend ostream& operator<<(ostream& os, const Employee& e)
is called for all three objects.
A simple way to make the friend operator << "virtual" is to define in each class a virtual function like for example
virtual std::ostream & out( std::ostream & ) const;
and define the (only) friend operator like
friend ostream& operator<<(ostream& os, const Employee& e)
{
return e.out( os );
}
The virtual function out need to be redefined in each derived class.
for example, I have a base class Unit and Unit has heirs, for example Soldier, Vampire. They have their own lives and damage. Is it possible to display data Vampire, Soldier using a separate class for example StateOfUnits where there is an overload of the output operator.
something like :
base class :
class Unit {
private:
int hpLimit;
int dmg;
int hp;
std::string name;
public:
Unit(int hpLimit = 100, int dmg = 10, const std::string& name = "noname");
~Unit();
int getDamage() const;
int getHP() const;
int getHpLimit() const;
const std::string& getName() const;
};
class that displays statistics:
class StateOfUnits {
///may be some code...
};
std::ostream& operator<<(std::ostream& out, const Unit& unit) {
out << "HP of " << unit.getName() << " is : " << unit.getHP() << "/" << unit.getHpLimit() << std::endl;
out << "Damage of " << unit.getName() << " is : " << unit.getDamage() << std::endl;
return out;
}
main:
int main() {
hp dmg name
Vampire vampire(100,25,"Vampire");
Soldier soldier(120, 20, "Soldier");
cout << soldier << endl;
cout << vampire << endl;
return 0;
}
I hope I explained it clearly.
Yes, if StateOfUnit is a base class:
#include <iostream>
using namespace std;
struct StateOfUnit
{
int hp;
int dmg;
string name;
StateOfUnit(int hp, int dmg, string name)
: hp(hp), dmg(dmg), name(name)
{}
friend ostream& operator<<(ostream& os, const StateOfUnit& s)
{
return os << s.hp << '\t' << s.dmg << '\t' << s.name;
}
};
struct Soldier : StateOfUnit
{
using StateOfUnit::StateOfUnit;
};
struct Vampire : StateOfUnit
{
using StateOfUnit::StateOfUnit;
};
int main() {
Vampire vampire(100,25,"Vampire");
Soldier soldier(120, 20, "Soldier");
cout << soldier << endl;
cout << vampire << endl;
return 0;
}
You have 2 classes Cats and Dogs and need to create a vector of shared pointers which stores the data from those 2 classes. Hints: polymorphism and keep in mind that classes can have similar fields.
So this is what I've done until now. I want to insert in that shared_ptr vector all the info Cats and Dogs classes have, but I don't know how. I only managed to insert in that vector the data from the base class.
#include <iostream>
#include <vector>
#include <memory>
class Animal
{
protected:
int tip;
std::string name;
int age;
public:
Animal(int t, std::string n, int a): tip(t), name(n), age(a) {}
friend std::ostream& operator<<(std::ostream& os, const Animal& a)
{
os << "Name: " << a.name << std::endl;
os << "Age: " << a.age << std::endl;
return os;
}
};
class Cats: public Animal
{
std::string race;
std::string pref_food;
public:
Cats(int t = 0, std::string n = "", int a = 0, std::string r = "", std::string mnprf = ""):
Animal(t, n, a), race(r), pref_food(mnprf) {}
friend std::ostream& operator<<(std::ostream& os, const Cats& c)
{
// auto n = static_cast<Animal> (c);
os << "Name: " << c.name << std::endl;
os << "Age: " << c.age << std::endl;
os << "race: " << c.race << std::endl;
os << "Fav food: " << c.pref_food << std::endl;
return os;
}
};
class Dog: public Animal
{
std::string disease;
std::string master;
public:
Dog(int t = 1, std::string n = "", int a = 0, std::string b = "", std::string s = "" ):
Animal(t, n, a), disease(b), master(s) {}
friend std::ostream& operator<<(std::ostream& os, const Dog& d)
{
os << "Name: " << d.name << std::endl;
os << "Age: " << d.age << std::endl;
os << "disease: " << d.disease << std::endl;
os << "master: " << d.master << std::endl;
return os;
}
};
template<typename T>
void add(std::vector<std::shared_ptr<Animal>>& vec, const T& a)
{
auto newptr = std::make_shared<Animal>(a);
vec.push_back(newptr);
}
int main()
{
std::vector<std::shared_ptr<Animal>> Animals;
Dog d(1,"Rex", 12, "idk", "Oscar");
Cats c(0,"Meaw", 11, "Sfinx", "Catfood");
add(Animals,d);
add(Animals,c);
for(auto i: Animals)
{
std::cout << *i;
}
}
There are a few problems with your code:
Animal lacks any virtual methods. At the very least, it needs a virtual destructor, so that the destructors of Cats and Dog are called correctly when shared_ptr<Animal> calls delete on its held Animal* pointer.
add() is creating an instance of Animal specifically, regardless of T. So your vector contains only real Animal objects. add() needs to create an instance of T instead. A std::shared_ptr<T> can be assigned to a std::shared_ptr<Animal> when T derives from Animal. Of course, add() is redundant, main() can just create and add the new objects directly to its vector without using add() at all.
When main() calls operator<< on an Animal, it will not call the operator<< defined by Cats or Dog, only the operator<< defined by Animal. This can be fixed by having operator<< in Animal call a virtual method that Cats and Dog override. There is no need to define operator<< in derived classes when the base class also has an operator<<.
Try this instead:
#include <iostream>
#include <vector>
#include <memory>
class Animal
{
protected:
int tip;
std::string name;
int age;
public:
Animal(int t, std::string n, int a): tip(t), name(n), age(a) {}
virtual ~Animal() {}
virtual void print(std::ostream& os) const
{
os << "Name: " << name << std::endl;
os << "Age: " << age << std::endl;
}
friend std::ostream& operator<<(std::ostream& os, const Animal& a)
{
a.print(os);
return os;
}
};
class Cat : public Animal
{
std::string race;
std::string pref_food;
public:
Cat(int t = 0, std::string n = "", int a = 0, std::string r = "", std::string mnprf = ""):
Animal(t, n, a), race(r), pref_food(mnprf) {}
void print(std::ostream& os) const override
{
Animal::print(os);
os << "race: " << race << std::endl;
os << "Fav food: " << pref_food << std::endl;
}
};
class Dog : public Animal
{
std::string disease;
std::string master;
public:
Dog(int t = 1, std::string n = "", int a = 0, std::string b = "", std::string s = ""):
Animal(t, n, a), disease(b), master(s) {}
void print(std::ostream& os) const override
{
Animal::print(os);
os << "disease: " << disease << std::endl;
os << "master: " << master << std::endl;
}
};
template<typename T>
void add(std::vector<std::shared_ptr<Animal>> &vec, const T &a)
{
auto newptr = std::make_shared<T>(a);
vec.push_back(newptr);
}
int main()
{
std::vector<std::shared_ptr<Animal>> Animals;
Dog d(1,"Rex", 12, "idk", "Oscar");
Cat c(0,"Meaw", 11, "Sfinx", "Catfood");
add(Animals, d);
add(Animals, c);
/* alternatively:
Animals.push_back(std::make_shared<Dog>(1,"Rex", 12, "idk", "Oscar"));
Animals.push_back(std::make_shared<Cat>(0,"Meaw", 11, "Sfinx", "Catfood"));
*/
for(auto &i: Animals)
{
std::cout << *i;
}
return 0;
}
Output:
Name: Rex
Age: 12
disease: idk
master: Oscar
Name: Meaw
Age: 11
race: Sfinx
Fav food: Catfood
Live Demo
I have the following class:
class Friend
{
public:
Friend();
~Friend(){}
void setName(string friendName){ name = friendName; }
void setAge(int friendAge) { age = friendAge; }
void setHeight(int friendHeight) { height = friendHeight; }
void printFriendInfo();
private:
string name;
int age;
float height;
};
//implementations
Friend::Friend()
{
age = 0;
height = 0.0;
}
//printing
void Friend::printFriendInfo()
{
cout << "Name : " << name << endl;
cout << "Age : " << age << endl;
cout << "Height : " << height << endl << endl;
}
And At this moment I can introduce the values in a vector, like this:
std::vector<Friend> regist(4, Friend());
regist[1].setAge(15);
regist[1].setHeight(90);
regist[1].setName("eieiei");
regist[2].setAge(40);
regist[2].setHeight(85);
regist[2].setName("random");
In debug, this solution works fine. But now I am trying to print the vector. So far without success.
for (int i = 0; i < regist.size(); i++) {
cout << regist[i]; //<-- error here
cout << '\n';
}
You might redesign a bit (in essence):
#include <iostream>
class Friend
{
public:
Friend();
// A more general name, const, and taking a stream.
void write(std::ostream&) const;
private:
std::string name;
int age;
float height;
};
Friend::Friend()
{
age = 0;
height = 0.0;
}
void Friend::write(std::ostream& stream) const
{
stream << "Name : " << name << std::endl;
stream << "Age : " << age << std::endl;
stream << "Height : " << height << std::endl << std::endl;
}
// Forward to the member function
inline std::ostream& operator << (std::ostream& stream, const Friend& object) {
object.write(stream);
return stream;
}
int main() {
Friend f;
std::cout << f;
}
Just call the printFriendInfo() member function:
for (int i = 0; i < regist.size(); i++) {
regist[i].printFriendInfo();
}
For
cout << regist[i];
to work, add a few accessor functions in Friend
string getName() const { return name; }
int getAge() const { return age; }
float getHeight() const { return height; }
and implement an overloaded operator<< function:
std::ostream& operator<<(std::ostream& out, Friend const& f)
{
out << "Name : " << f.getName() << std::endl;
out << "Age : " << f.getAge() << std::endl;
out << "Height : " << f.getHeight() << std::endl;
return out;
}
I am trying to create a base class which is a template class and accepts, as a templace, some class. This base class in the parent class of two other classes which are themselves the parents of the final class. Thus, I have the traditional diamond problem in c++ with the addition that the root base class is a template class. Using virtual inheritance here does not quite do the trick.
Edit: Included some code (and corrected typos)
#include<iostream>
#include<string>
using namespace std;
template<class TemplateT>
class MainMaster {
protected:
std::string name;
int number;
TemplateT variableProp;
public:
explicit MainMaster(std::string, int);
void setName(std::string);
std::string getName();
void printName();
void setNumber(int);
int getNumber();
void printNumber();
void printMasterProperties(std::string);
void setVarProp(TemplateT);
TemplateT getVarProp();
};
template<class TemplateT>
MainMaster<TemplateT>::MainMaster(std::string nameIn, int numIn){
setName(nameIn);
setNumber(numIn);
}
template<class TemplateT>
void MainMaster<TemplateT>::setName(std::string nameIn){ name = nameIn; }
template<class TemplateT>
std::string MainMaster<TemplateT>::getName(){ return name; }
template<class TemplateT>
void MainMaster<TemplateT>::printName(){ cout << "Master's name is " << name << endl; }
template<class TemplateT>
void MainMaster<TemplateT>::setNumber(int numIn){ number = numIn; }
template<class TemplateT>
int MainMaster<TemplateT>::getNumber(){ return number; }
template<class TemplateT>
void MainMaster<TemplateT>::printNumber(){ cout << name << "'s number is " << number << endl; }
template<class TemplateT>
void MainMaster<TemplateT>::printMasterProperties(std::string pre = ""){
cout << pre << "Master Properties" << endl
<< pre << "-Number: " << number << endl;
}
class ChildOne: public virtual MainMaster<std::string>{
protected:
std::string propOne;
public:
// using MainMaster::MainMaster;
ChildOne(std::string nameIn, int numIn, std::string p1);
void printName();
void setPropOne(std::string);
std::string getPropOne();
void printOnesProps(std::string);
};
ChildOne::ChildOne(std::string nameIn, int numIn, std::string p1): MainMaster<std::string>(nameIn,numIn){
setPropOne(p1);
}
void ChildOne::printName(){ cout << "ChildOne's name is " << name << endl; }
void ChildOne::setPropOne(std::string propIn){ propOne = propIn; }
std::string ChildOne::getPropOne(){ return propOne; }
void ChildOne::printOnesProps(std::string pre = ""){
printMasterProperties("-");
cout << pre << "One Properties" << endl
<< pre << "-PropOne: " << propOne << endl;
}
class ChildTwo: public virtual MainMaster<int>{
protected:
std::string propTwo;
public:
ChildTwo(std::string nameIn, int numIn, std::string p2);
void printName();
void setPropTwo(std::string);
std::string getPropTwo();
void printTwosProps(std::string);
};
ChildTwo::ChildTwo(std::string nameIn, int numIn, std::string p2): MainMaster<int>(nameIn,numIn){
setPropTwo(p2);
}
void ChildTwo::printName(){
cout << "ChidTwo's name is " << name << endl;
}
void ChildTwo::setPropTwo(std::string propIn){ propTwo = propIn; }
std::string ChildTwo::getPropTwo(){ return propTwo; }
void ChildTwo::printTwosProps(std::string pre = ""){
printMasterProperties("-");
cout << pre << "Two Properties" << endl
<< pre << "-PropTwo: " << propTwo << endl;
}
class FinalChild: public ChildOne, public ChildTwo{
protected:
double finalProp;
public:
FinalChild(std::string nameIn, int num, std::string prop1 ,std::string prop2, double pFinal);
void printFinalProps(std::string);
};
FinalChild::FinalChild(std::string nameIn, int num, std::string prop1 ,std::string prop2, double pFinal):
ChildOne(nameIn, num, prop1),
ChildTwo(nameIn, num, prop2),
MainMaster(nameIn, num){
finalProp = pFinal;
}
void FinalChild::printFinalProps(std::string pre = ""){
printMasterProperties("-");
cout << pre << name << "'s Final Properties" << endl;
cout << pre << "-Number: " << number << endl;
cout << pre << "-PropOne: " << propOne << endl;
cout << pre << "-PropTwo: " << propTwo << endl;
cout << pre << "-finalProp " << finalProp << endl;
}
int main () {
MainMaster<char> master("Master", 0);
ChildOne child1("Child1",1,"P1One");
ChildTwo child2("Child2",2,"P2Two");
FinalChild finalC("FinalChild", 3, "P1Final", "P2Final", 3.0);
master.printMasterProperties();
child1.printOnesProps();
child2.printTwosProps();
finalC.printFinalProps();
}