Map of derived functions - c++

I have Base and Derived class
Base :
class Person{
public:
Person(string name , int age ){
this -> name = name;
this -> age = age;
}
virtual void getInfo(){
cout << "Person " << name << " " << age;
}
protected:
string name;
int age;
};
Derived:
class Kid : public Person{
public:
Kid(string name, int age):Person(name,age){};
virtual void getInfo( ){
cout << "Kid " << name << " " << age;
}
};
class Adult : public Person{
public:
Adult(string name, int age):Person(name,age){};
virtual void getInfo( ){
cout << "Adult " << name << " " << age;
}
};
When i do something like
map<string ,Person*> m;
Person *one;
Person *three;
Kid two("Mathew",15);
Adult four("JOhn",55);
three = &four;
one = &two;
m["first"] = one;
m["second"] = three;
for( auto &x : m )
x.second-> getInfo();
return 0;
It nicely prints info as it should // "Adult" for adult class and "Kid" for kid class
however when i edit the class and move the map into base class. e.g and create Add method.
class Person{
public:
Person(string name , int age ){
this -> name = name;
this -> age = age;
}
virtual void getInfo(){
cout << "Person " << name << " " << age;
}
void add( string name , Person a){
Person *one = &a;
m[ name ] = one;
}
void print(){
for( auto &x: m )
x.second -> getInfo()
}
protected:
string name;
int age;
map< string , Person*> m;
};
Person one("John", 25);
one.add("first",Kid("Mathew",15));
one.add("second",Adult("Leo",55));
one.print();
It throws seg fault , why is this happening? Its basicly the same implementation with using of method. What causes the seg fault? Is there a way how to fix it?
// EDIT
I tried using unique_ptr redecaring map as
map< string , unique_ptr<Person>> m;
AddField (string name , Person a ){
m[name] = ( unique_ptr<Person> (a));
return *this;
}
or
properties[name] = unique_ptr<Person> ( new Person( a ));
or
AddField (string name , Person a ){
CData *one = unique_ptr<Person>(new Person(a));
m[name] = one ;
return *this;
}
I am not experienced with unique/share ptr.
This threw
‘std::unique_ptr’ to ‘Person*’

Firstly, let's understand what the map is actually storing:
map< string , Person*> m;
This map binds a string to a Person*, which is a memory address pointing to a person. The map does not actually store the person instance, only its memory address.
Now let's analyze your two situations.
map<string ,Person*> m;
// Allocating space for two memory addresses on the stack:
Person *one;
Person *three;
// Creating two instances on the stack:
Kid two("Mathew",15);
Adult four("JOhn",55);
// Setting the pointers to the memory addresses of the instances on the stack:
three = &four;
one = &two;
m["first"] = one;
m["second"] = three;
for( auto &x : m )
x.second-> getInfo();
return 0;
// End of the function: now all objects are destroyed in reverse order.
The instances two and four live on the stack and are destroyed at the end of the scope (after return 0;). Taking their memory addresses and storing them into one and three is fine, as the pointers will outlive two and four.
Person one("John", 25);
// Creating a Kid instance without a name (temporary).
// The Kid instance goes out of scope immediately and is destroyed:
one.add("first",Kid("Mathew",15));
// Creating an Adult instance without a name (temporary).
// The Adult instance goes out of scope immediately and is destroyed:
one.add("second",Adult("Leo",55));
one.print();
The issue here is that the instances you are creating are destroyed too soon. You need to manage their lifetime properly to ensure that the memory address you're inserting into the map does not outlive the data in the pointed memory location.
Another major issue is that you're accepting add's Person a parameter by value. This will create a copy of the passed instance.
// Copy the passed instance:
void add( string name , Person a){
// Take memory address of the copied instance:
Person *one = &a;
m[ name ] = one;
// The copied instance is destroyed here!
}
You should take a as a reference, in order to avoid copies and object slicing:
void add( string name , Person& a){
m[ name ] = &a;
}
Here's a working example, after correcting a's signature:
Kid k("Mathew",15);
Adult a("Leo",55);
// k and a will outlive one.
Person one("John", 25);
one.add("first", k);
one.add("second", a);
one.print();
// one gets destroyed.
// a gets destroyed.
// k gets destroyed.

I had a go at trying to solve your issue and I came up an initial version of this. Which I'm not really happy with.
#include<iostream>
#include<map>
#include<memory>
#include<string>
/* used to simplify example code (not a good
idea in production code especially header files)
*/
using namespace std;
class Person
{
public:
virtual void getInfo() const = 0;
virtual ~Person()
{};
void add(std::shared_ptr<Person> a)
{
m_[a->name_] = a;
}
void print() const
{
getInfo();
for( auto &x: m_ )
x.second->getInfo();
}
protected:
Person(const string& name, int age)
: name_(name), age_(age)
{}
string name_;
int age_;
map<string , std::shared_ptr<Person>> m_;
};
class Kid : public Person
{
public:
Kid(const string& name, int age)
: Person(name, age)
{};
virtual void getInfo() const override
{
cout << "Kid " << name_ << " " << age_ << '\n';
}
};
class Adult : public Person
{
public:
Adult(const string& name, int age)
: Person(name, age)
{};
virtual void getInfo() const override
{
cout << "Adult " << name_ << " " << age_ << '\n';
}
};
int main()
{
auto a = Adult("steve", 35);
auto k1 = make_shared<Kid>("ben", 7);
auto k2 = make_shared<Kid>("emily", 12);
a.add(k1);
a.add(k2);
a.print();
}
I used shared_ptr as I'm guessing later you might want to retrieve those Persons from the map and return them from a getter call. So in that case unique_ptr makes no sense.
I think this version puts too much burden on the caller to create the shared_ptrs. Without knowing exactly what you plan to do though its difficult to suggest an alternative.

Related

Runtime error when vector in class constructor?

Hi I am unable to use a vector in the constructor. I'm trying to parse a vector that contains [x,y] coordinates into the object.
The errors I've gotten are runtime error and bad alloc.
Is there something I'm missing?
Do I have to use dynamic memory allocation?
ShapeTwoD(Parent Class of Child Class Square):
class ShapeTwoD {
protected:
string name;
bool containsWarpSpace;
vector<string> vect;
private:
public:
ShapeTwoD() {}
ShapeTwoD(string name, bool containsWarpSpace, vector<string> vect) {
this->vect = vect;
this->name = name;
this->containsWarpSpace = containsWarpSpace;
}
Class Square that is a child of ShapeTwoD:
class Square : public ShapeTwoD {
public:
Square() : ShapeTwoD(name, containsWarpSpace, vect) {
this->vect = vect;
this->name = name;
this->containsWarpSpace = containsWarpSpace;
}
~Square() {}
};
Main Function:
vector<string> temp;
string merge;
for (int i = 0; i < 4; i++) {
cout << "Please enter x-ordinate of pt " << i + 1 << " :";
cin >> x;
cout << "Please enter y-ordinate of pt " << i + 1 << " :";
cin >> y;
merge = x + ", " + y;
temp.push_back(merge);
}
Square obj;
obj.setName(shape);
obj.setCoord(temp);
if (specialtype == "ws") {
obj.setContainsWarpSpace(true);
}
else if (specialtype == "ns") {
obj.setContainsWarpSpace(false);
}
myvector.push_back(obj);
temp.clear();
cout << "\nRecords successfully stored. Going back to main menu ...\n"
<< endl;
}
In your Square constructor, you are not passing any arguments:
Square() : ShapeTwoD(name,containsWarpSpace,vect){
^^^^^^^^^^^^^^^^^^^^^^^^^^^
That means that the name, containsWarpSpace and vect refer to the parent class fields, which haven't been initialized yet (because that's the job of the ShapeTwoD constructor). So you are taking uninitialized variables and passing them into the constructor to initialize those same variables. More explicitly what you are doing is
Square():ShapeTwoD(this->ShapeTwoD::name,
this->ShapeTwoD::containsWarpSpace, this->ShapeTwoD::vect){
You should either pass them in:
Square(string name, bool containsWarpSpace, vector<string> vect)
:ShapeTwoD(name,containsWarpSpace,vect) {
or pass a sensible default:
Square() : ShapeTwoD("", false, {}) {
The problem is:
merge = x + ", " + y;
The ", " is a const char[3] (a null terminated character array). As an array, it decays to a pointer (const char *), which is offset by x+y as a result of summation with int. The resultant pointer refers to an unknown memory location. Next null byte is not guaranteed to reside in accessible address range; even if such byte is in an accessible address, the output would not be meaningful; because you are triggering UB.
You can fix it like this:
merge = std::to_string(x) + ", " + std::to_string(y);
Regards,
FM.

Diamond problem with Multiple inheritance C++

I have a homework task with a given main.cpp code which is not allowed to be changed. According to that main.cpp and simple input and output(which is down below) example I must to finish the program.
My tries are: I'm trying to create 4 classes, class Person; class Worker; class Student; class InService; in my main function through instantiating an object of InService class I pass 4 parameters (name, sex, studentNo, workerNo); and with help of pointer of type of Base class, have the desired output. The error it shows is:
[Error] no unique final overrider for 'virtual std::string Person::getName()' in 'InService'
[Error] no unique final overrider for 'virtual int Person::getSex()' in 'InService'
I've tried to use virtual inheritance for that, but I can't really figure out how to solve this problem. I did some research on virtual inheritance, and referenced to other experts answers, but still getting confused with whole OOP stuff.
//Inservice.h
#include<string>
using namespace std;
class Person{
public:
Person();
~Person();
string name;
int sex;
virtual string getName() = 0;
virtual int getSex() = 0;
};
///////////////////////////////////////////////////
class Student:virtual public Person{
public:
Student();
~Student();
string sno;
virtual string getName() {
return name;
}
virtual int getSex(){
return sex;
}
string getSno(){
return sno;
}
};
//////////////////////////////////////////////////
class Worker:virtual public Person{
public:
Worker();
~Worker();
string wno;
virtual std::string getName(){
return name;
}
virtual int getSex(){
return sex;
}
string getWno(){
return wno;
}
};
///////////////////////////////////////////////////////
class InService: public Student, public Worker{
public:
InService(string _name, int _sex, string _sno, string _wno){
Person::name = _name;
Person::sex - _sex;
Worker::wno = _wno;
Student::sno = _sno;
}
};
///////////////////////////////////////////////////////
//main.cpp
#include <iostream>
#include "inservice.h"
using namespace std;
int main() {
string name, sno, wno;
int sex;
cin >> name;
cin >> sex;
cin >> sno;
cin >> wno;
InService is(name, sex, sno, wno);
Person* p = &is;
Student* s = &is;
Worker* w = &is;
cout << p->getName() << endl;
cout << p->getSex() << endl;
cout << s->getName() << endl;
cout << s->getSex() << endl;
cout << s->getSno() << endl;
cout << w->getName() << endl;
cout << w->getSex() << endl;
cout << w->getWno() << endl;
return 0;
}
Suppose my input is:
Jack
1 //1-for male; 0 -for female
12345678 //studentNo
87654321 //workerNo
I expect the output to be:
Jack
1
12345678
Jack
1
87654321
InService(string _name, int _sex, string _sno, string _wno){
Person::name = _name;
Person::sex - _sex;
Worker::wno = _wno;
Student::sno = _sno;
}
There's a typo there, Person::sex - _sex; should be Person::sex = _sex;
Also you can remove name and sex virtual function and have it just a standard function in Person, since it's exactly the same for all classes that derive from it. That will remove the ambiguity of which getName and getSex function that InService class virtual table needs to point to.

Derived Class C++ [duplicate]

This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 6 years ago.
I know that it can be a stupid but I even don't know how to name this question. I'm non native English. I learn C++ from a book and there is a program which shows name and pay rate of employee (base class) and Manager (derived class) with added bool variable salaried. Here is the source code:
//base class
class Employee {
private:
string name;
double pay;
public:
Employee() {
name = "";
pay = 0;
}
Employee(string empName, double payRate) {
name = empName;
pay = payRate;
}
string getName() const {
return name;
}
void setName(string empName) {
name = empName;
}
double getPay() const {
return pay;
}
void setPay(double payRate) {
pay = payRate;
}
string toString() {
stringstream stm;
stm << name << ": " << pay;
return stm.str();
}
};
//derived class
class Manager : public Employee {
private:
bool salaried;
public:
Manager(string name, double payRate, bool isSalaried)
:Employee(name, payRate)
{
salaried = isSalaried;
}
bool getSalaried() {
return salaried;
}
};
int main()
{
Employee emp1("Mary Smith", 15.00);
cout << "Employee name: " << emp1.getName() << endl;
cout << "Employee pay rate: " << emp1.getPay() << endl;
Manager emp2("Bob Brown", 1500, true);
cout << "Employee name: " << emp2.getName() << endl;
cout << "Employee pay rate: " << emp2.getPay() << endl;
cout << "Is Salaried: " << emp2.getSalaried() << endl;
return 0;
}
Can someone explain me why this part
:Employee(name, payRate)
must be added to code to work properly?
The part
:Employee(name, payRate)
you mention is used to call the constructor
Employee(string empName, double payRate)
of the base class Employee before executing the body of the constructor
Manager(string name, double payRate, bool isSalaried)
of the derived class Manager.
It calls the base class's (Employee) constructor and passes the name and payRate to it because they are members of Employee.
:Employee(name, payRate)
is the initialisation of the base class that class Manager inherits.
In fact without this line the code should compile fine(because you have a default constructor for Employee), but the fields inherited from Employee will not get properly initialized in emp2. What this portion of the code does is to call the constructor of Employee to initialize the fields inherited from that class.
What come after the colon on the constructor called initialization list and in your case it just initiate the base class with the suitable constructor
The code can work properly even without the constructor(i.e..you can use the default constructor to accept the variables and implement two methods for filling the name and pay.)
class Employee {
private:
string name;
string temp_name;
double temp_pay;
double pay;
public:
Employee() {
name = temp_name;
pay = temp_pay;
}
void getTempname(string tem){temp_name = tem;}
void getTemppay(double py){ temp_pay = pay;}
};

C++: Derived classes, "no matching constructor" error

I've been working on this assignment for a while. Here's the instructions:
You are to design an abstract class called Employee whose members are
as given below (make them protected):
Data members: char *name, long int ID
Two constructors: A Default constructor // intitialize data memebrs to
the default values and a copy constructor
Methods: setPerson (char *n, long int id) //allows user to set
information for each person A function called Print () // should be a
virtual function, that prints the data attributes of the class. and a
destructor
Also define two classes that derived from class Employee, called
Manager and Secretary. Each class should inherit all members from the
base class and has its own data members and member functions as well.
The Manager should have a data member called degree for his/her
undergraduate degree (e.g. diploma, bachelor, master, doctor), the
Secretary should have her contract (can be a Boolean value 1/0 for
permanent/temporary).
All member functions of derived class should be overrided from their
base class.
Write the following main() to test your classes
int main() {
Employee * p = new Manager(“Bruce Lee”, 0234567, “Dr.”);
P.print();
Secretary p2;
p2.setPerson(“Wilma Jones”, 0341256, “permanent”);
delete p;
p = & p2;
p.Print();
return 0;
}
This is everything I've come up with so far, but I'm pretty sure it's riddled with mistakes and that my arguments and variable types are all off.
#include <iostream>
using namespace std;
class Employee{
protected:
char *name;
long int ID;
public:
Employee();
Employee(Employee&);
void setPerson(char * n, long int eID) {
name = n;
ID = eID; };
virtual void Print(){
cout << "Name: " << name << endl;
cout << "ID: " << ID << endl; };
};
class Manager: public Employee {
protected:
char *degree;
public:
void setPerson(char * n, long int eID, char * d){
name = n;
ID = eID;
degree = d;
};
void Print() {
cout << "Name: " << name << endl;
cout << "ID: " << ID << endl;
cout << "Degree: " << degree << endl;
};
};
class Secretary: public Employee {
protected:
bool contract;
public:
void setPerson(char * n, long int eID, string c){
name = n;
ID = eID;
if (c == "permanent") contract = true;
else contract = false;
};
void Print(){
cout << "Name: " << name << endl;
cout << "ID: " << ID << endl;
cout << "Contract: " << contract << endl;
};
};
int main() {
Employee * P = new Manager("Bruce Lee", 0234567, "Dr.");
P.Print();
Secretary P2;
P2.setPerson("Wilma Jones", 0341256, "permanent");
delete P;
P = & P2;
P.Print();
return 0;
}
I'm getting an error on line 62 (the first line of the main code):
No matching constructor for initialization of Manager
I've tried reading similar questions, but they haven't helped me much. I think the most confusing thing is contract being a bool value and the use of char arguments. Any guidance at all is appreciated.
The error you're getting is pretty straight-forward: you don't have any constructor for Manager (or Employee) that takes a string, integer (?), and string as arguments.
You have declared the constructor employee but not defined it.
Look at the class employee, Under publc you have declared
Employee();
Employee(Employee&);
But you have not defined the function. You need
Employee :: Employee()
{
bla bla bla
}
and another one for the other signature.

Class Inheritance c++

i have a base class product and a child class multiBuyProduct
class Product
{
public:
Product(std::string name, Amount price);
}
class MultiBuyProduct :public Product
{
public:
MultiBuyProduct(std::string aName, Amount price, int minDiscountedQuantity, int discountedPercent);
now obviously some of the constructor variables are the same but in my main class i assume if i want the functionality of multiBuyProduct i need to call it? or can i call product and pass values for the multiBuyProduct constructor into a parameter that is expecting a product?
Below shows a method where this is used
void ShoppingCart::add(Product p, int quantity, bool end)
{
}
Above is the method i want to sent the parameters to but i dont know if i need to change the code for this method to accept a MultiBuyProduct or ...??
EDIT: sorry forgot to mention 'Amount' is a class that takes two integers
Amount amount(0,1);
You should change ShoppingCart::add something like below, to achieve polymorphic behavior:
void ShoppingCart::add(Product *p, int quantity, bool end)
{
p->doSomething();
// ...
Product *product = p;
product->doSomething();
// ...
}
Usage:
ShoppingCart shoppingCart;
MultiBuyProduct multiBuyProduct("Paper", Amount(0,1), 1, 1);
shoppingCart.add(&multiBuyProduct, 1, true);
You will probably want to add a virtual method in Product, say, Amount Product::calculatePrice(int quantity), and override it in MultiBuyProduct so that it performs the correct calculation based on minDiscountedQuantity. Then, call this method from add(). Furthermore, you need to pass a reference (Product&) or a pointer (Product*) to add() in order for virtual method invocation to work.
You should change a few things.
You need a type of pointer or reference for polymorphic behaviour.
You need to call the base class constructor.
You need to override your virtual methods.
You should watch out for proper memory management once you rely on pointers.
You should try to be const correct.
Consider this example below:
#include <string>
#include <iostream>
#include <vector>
#include <memory>
#include <sstream>
class Product
{
private:
double Price;
std::string Name;
public:
Product(const std::string& name, double price)
: Price(price),
Name(name)
{
std::cout << "Created " << name << " for $" << price << std::endl;
}
virtual std::string GetName() const
{
return Name;
}
virtual double GetPrice() const
{
return Price;
}
};
class MultiProduct :public Product
{
private:
int Quantity;
public:
MultiProduct(const std::string& name, double price, int quantity)
: Product(name, price),
Quantity(quantity)
{
std::cout << "Created " << quantity << "x " << name << " for $" << price << " each." << std::endl;
}
virtual double GetPrice() const
{
return Product::GetPrice() * Quantity;
}
virtual std::string GetName() const
{
std::stringstream s;
s << Product::GetName();
s << " x";
s << Quantity;
return s.str();
}
};
class ShoppingCart
{
private:
std::vector< std::shared_ptr<Product> > Cart;
public:
void Add( std::shared_ptr<Product> product )
{
Cart.push_back( product );
}
void PrintInvoice() const
{
std::cout << "Printing Invoice:" << std::endl;
for( auto it = Cart.begin() ; it != Cart.end() ; ++it )
{
std::cout << (*it)->GetName() << ": " << (*it)->GetPrice() << std::endl;;
}
}
};
int main()
{
ShoppingCart cart;
cart.Add( std::shared_ptr<Product>( new Product( "cheese", 1.23 ) ) );
cart.Add( std::shared_ptr<Product>( new MultiProduct( "bread", 2.33, 3 ) ) );
cart.Add( std::shared_ptr<Product>( new Product( "butter", 3.21 ) ) );
cart.Add( std::shared_ptr<Product>( new MultiProduct( "milk", 0.55, 5 ) ) );
cart.Add( std::shared_ptr<Product>( new Product( "honey", 5.55 ) ) );
cart.PrintInvoice();
std::cout << "Press any key to continue" << std::endl;
std::cin.get();
return 0;
}