I have a question about building a method :
virtual std::string getPerson() const;
I have a child class Player and a the parent is Person.
Class Player :
class Player : public Person {
public:
Player(const std::string& p_name,const std::string& p_lastname, const int& p_age, const std::string& p_position);
virtual ~Player();
virtual Person* clone() const;
std::string getPosition() const;
virtual std::string getPerson() const;
private:
std::string m_position;
};
Class Person :
class Person {
public:
Person(const std::string& p_name,const std::string& p_lastname, const int& p_age);
virtual ~Person();
virtual std::string getPerson() const;
std::string getName() const;
std::string getLastName() const;
int getAge() const;
private:
std::string m_name;
std::string m_lastname;
int m_age;
};
When I try to add this in Player :
std::string Player::getPerson()
{
ostringstream os;
os << "Name :" << getName() << "\n";
os << "LastName :" << getLastName()() << "\n";
os << "Age :" << getAge()() << "\n";
os << "Position :" << getPosition();
return os.str();
}
I get Member declaration not found
I can't get it to work I would need to print something like this :
Name : John
Lastname : Smith
Age : 22
Position : Goalie
You missed the const at the end of the function signature. This should work:
std::string Player::getPerson() const
{
ostringstream os;
os << "Name :" << getName() << "\n";
os << "LastName :" << getLastName()() << "\n";
os << "Age :" << getAge()() << "\n";
os << "Position :" << getPosition();
return os.str();
}
But please mind what I said in the comment and change the function's name, or even better, make your class work with std::ostream by means of overloading operator<<.
Simple thing:
std::string getPerson() const;
is not the same as:
std::string getPerson();
If you can use c++11 use the override keyword, that protects you from such kind of mistakes. In your case the compiler detects the problem. But if you have other variants you maybe declare a new method instead of overloading!
Related
Let us look at the following class:
ProjectManager.hh
#ifndef INPUT_CPP_FILES_PROJECT_MANAGER_HH
#define INPUT_CPP_FILES_PROJECT_MANAGER_HH
#include <string>
#include "Employee.hh"
#include "Programmer.hh"
#include "Tester.hh"
namespace OrganizationNamespace {
class ProjectManager : public Programmer, public Tester {
public:
ProjectManager():Employee(), Programmer(), Tester()
{}
explicit ProjectManager(const std::string& id):Employee(id), Programmer(), Tester()
{}
ProjectManager(std::string&id, std::string &name):Employee(id, name), Programmer(), Tester()
{}
ProjectManager(std::string &id, std::string &name, std::string &programming_language):Employee(id, name), Programmer(programming_language), Tester()
{}
ProjectManager(std::string &id, std::string &name, std::string &programming_language, std::string &tool):Programmer(programming_language), Tester(tool),Employee(id, name)
{}
ProjectManager(ProjectManager const & pm)
{
this->id_ = pm.id_;
this->name_ = pm.name_;
this->programming_language_ = pm.programming_language_;
this->tool_ = pm.tool_;
}
void print() const {
std::cout << "(" << Employee::id_ << ", " << Employee::name_ << ", " << Programmer::programming_language_ << "," << Tester::tool_ << ")"
<< std::endl;
}
};
}
#endif //INPUT_CPP_FILES_PROJECT_MANAGER_HH
main.cpp
#include "Employee.hh"
#include "Programmer.hh"
#include "ProjectManager.hh"
int main()
{
std::string id = "id";
std::string name = "name";
std::string programming_language = "programming-language";
std::string testing_tool = "testing-tool";
OrganizationNamespace::ProjectManager pm(id, name, programming_language, testing_tool);
pm.print();
}
Output
C:\Users\pc\source\repos\input_cpp_files\cmake-build-debug\input_cpp_files.exe
(id, name, ,)
Process finished with exit code 0
As we can see the program is not giving the correct output.
The expected output is:
C:\Users\pc\source\repos\input_cpp_files\cmake-build-debug\input_cpp_files.exe
(id, name, programming-language, testing-tool)
Process finished with exit code 0
How can I implement constructors in ProjectManager so that they give the correct output?
Additional Source Code
Employee.hh
#ifndef INPUT_CPP_FILES_EMPLOYEE_HH
#define INPUT_CPP_FILES_EMPLOYEE_HH
#include <iostream>
#include <string>
namespace OrganizationNamespace {
class Employee {
protected:
std::string id_;
std::string name_;
public:
Employee() : id_ (""), name_("") {}
Employee(const std::string &id) : id_(id), name_("") {}
Employee(const std::string &id, const std::string &name) : id_(id), name_(name) {}
Employee(Employee const & emp)
{
this->id_ = emp.id_;
this->name_ = emp.name_;
}
void print() const
{
std::cout << "(" << id_ << ", " << name_ << ")" << std::endl;
}
};
}
#endif //INPUT_CPP_FILES_EMPLOYEE_HH
Programmer.hh
#ifndef INPUT_CPP_FILES_PROGRAMMER_HH
#define INPUT_CPP_FILES_PROGRAMMER_HH
#include "Employee.hh"
namespace OrganizationNamespace {
class Programmer : public virtual Employee {
protected:
std::string programming_language_;
public:
Programmer() : Employee(), programming_language_("") {}
Programmer(std::string id) : Employee(id) {}
Programmer(std::string id, std::string name) : Employee(id, name) {}
Programmer(std::string id, std::string name, std::string programming_language) : Employee(id, name),
programming_language_(
programming_language) {}
void print() const {
std::cout << "(" << id_ << ", " << name_ << ", " << programming_language_ << ")" << std::endl;
}
};
}
#endif //INPUT_CPP_FILES_PROGRAMMER_HH
Tester.hh
#ifndef INPUT_CPP_FILES_TESTER_HH
#define INPUT_CPP_FILES_TESTER_HH
#include <string>
#include "Employee.hh"
namespace OrganizationNamespace {
class Tester : public virtual Employee {
protected:
std::string tool_;
public:
Tester() : Employee(), tool_("") {}
Tester(std::string id) : Employee(id) {}
Tester(std::string id, std::string name) : Employee(id, name) {}
Tester(std::string id, std::string name, std::string tool) : Employee(id, name), tool_(tool) {}
void print() const {
std::cout << "(" << id_ << ", " << name_ << ", " << tool_ << ")" << std::endl;
}
};
}
#endif //INPUT_CPP_FILES_TESTER_HH
The problem is that when you call the ProjectManger cosntructor you also call the overloaded cosntructors of Programmer and Tester, the versions you are calling are those which take as parameter one std::string, those constructors change the value of Employee::id_, actually you never changed other values.
For fixing the problem you must change
ProjectManager(std::string& id, std::string& name, std::string& programming_language, std::string& tool) :
Employee(id, name),
Programmer(programming_language),
Tester(tool)
{}
in
ProjectManager(std::string& id, std::string& name, std::string& programming_language, std::string& tool) :
Employee(id, name),
Programmer("","",programming_language),
Tester("","",tool)
{}
Your 4-parameter ProjectManager constructor calls the 1-parameter Programmer constructor, which does not set the programming_language_ member. The same for the Tester constructor.
So neither of the member variables for your two classes get anything other than default initialized to empty strings.
The solution is to pass the proper values in the proper parameters, and construct the base classes in the correct order.
namespace OrganizationNamespace {
class ProjectManager : public Programmer, public Tester {
public:
// ...
ProjectManager(std::string &id, std::string &name, std::string &programming_language):
Employee(id, name), Programmer(id, name, programming_language), Tester()
{}
ProjectManager(std::string &id, std::string &name, std::string &programming_language, std::string &tool):
Employee(id, name), Programmer(id, name, programming_language), Tester(id, name, tool)
{}
// ...
};
Even though the id and name parameters won't be used by the Programmer or Tester constructors (because the Employee base class they are passed to is virtual and will be constructed by the most derived object, ProjectManager), we still pass in those values. There are a couple of reasons for that.
Because we already have these string objects, and the constructors take their parameters as references, we avoid the overhead of constructing temporary string objects that will be unused.
The code does not rely on the assumption that the id and name paramaters are unused. It is possible that a future change to the constructors will make use of one or both parameters. By passing in the expected values that can avoid future bugs.
In the below code, I am trying to override the price() function for both Taxed and Untaxed, however, they both call the parent virtual function instead of the overriden one that was given to them. What did I mess up?
Header file:
#ifndef PRODUCT_H
#define PRODUCT_H
#include <string>
#include <iostream>
class Product {
protected:
int _quantity;
double _cost;
std::string _name;
public:
Product(std::string name, double cost);
virtual ~Product();
void set_quantity(int quantity);
virtual double price() const;
friend std::ostream & operator<< (std::ostream &ost, const Product &product);
};
std::ostream & operator<< (std::ostream &ost, const Product &product);
class Taxed : public Product{
private:
static double _tax;
public:
using Product::Product;
virtual ~Taxed();
static void set_tax_rate(double sales_tax);
double price() const override;
};
class Taxfree : public Product{
public:
using Product::Product;
virtual ~Taxfree();
double price() const override;
};
#endif //PRODUCT_H
.cpp file:
#include <string>
#include <iomanip>
#include <iostream>
#include "product.h"
Product::Product(std::string name, double cost){
_name = name;
_cost = cost;
_quantity = NULL;
};
Product::~Product(){};
void Product::set_quantity(int quantity){
if (quantity < 0){
std::cerr << "Cannot have negative quantity";
}
_quantity = quantity;
};
double Product::price() const {
return 2;
};
std::ostream & operator<< (std::ostream &ost, const Product &product){
if (product._quantity > 0)
ost << product._name << " (" << product._quantity << " # " << std::fixed << std::setprecision(2) << std::setfill('0') << product.price() << ")";
else
ost << product._name << " (" << std::fixed << std::setprecision(2) << std::setfill('0') << product.price() << ")";
return ost;
};
double Taxed::_tax = 0.0825;
Taxed::~Taxed(){};
void Taxed::set_tax_rate(double sales_tax) {
Taxed::_tax = sales_tax;
};
double Taxed::price() const{
return _quantity * _cost * (1+_tax);
}
Taxfree::~Taxfree(){};
double Taxfree::price() const{
return _quantity * _cost;
}
You are experiencing object slicing. By storing a std::vector<Product>, you are actually creating instances of the base Product class and losing your instances of Taxed and Taxfree. In products.push_back(Taxfree("Apple", 2)), the Taxfree is passed to the compiler-generated copy constructor Product(const Product&), because a Taxfree object can bind to a const Product&.
Had you removed the base implementation of price() and made it a pure virtual function with virtual double price() const = 0;, you would have noticed this problem when your program failed to compile (because Product would become an abstract class and constructing it would no longer be possible).
Instead, you will need to use something like std::vector<std::shared_ptr<Product>>:
std::vector<std::shared_ptr<Product>> products;
products.push_back(std::make_shared<Taxfree>("Apple", 2));
products.push_back(std::make_shared<Taxed>("Iron",1.75));
products.push_back(std::make_shared<Taxfree>("Soda",2.5));
products.push_back(std::make_shared<Taxfree>("Lemon",2.5));
(I'd suggest unique_ptr instead, but it looks like you want the products and cart to contain the same object. Or, you could use unique_ptr and just create copies of the products, which is probably better if you plan to mutate them.)
I am having an issue with the class inheritance in my code. Here is what I am doing: I have two classes, one called Employee and the second called Manager. Employee is the base class, it has a function that prints Business card, containing the name of the company and the function name(), that prints the name of the employee. Class Manager is a derived class and inherits (public: Employee). When I try to print the same business card for the manager, it does not display the name, only the company name. What could be the problem?
Below is the little snippet of, first, the Employee class:
class Employee {
public:
// Constructor
Employee(const char* name, double salary) : _name(name), _salary(salary) {}
Employee() : _name(" "), _salary(0) {} // default constructor
// Accessors
const char* name() const { return _name.c_str() ; }
double salary() const { return _salary ; }
// Modifyers (if needed)
double set_salary( double salary) {
_salary = salary;
return _salary;
}
// Print functions
void businessCard(ostream& os = cout) const {
os << " +------------------+ " << endl
<< " | ACME Corporation | " << endl
<< " +------------------+ " << endl
<< " " << name() << endl ;
}
private:
string _name ;
double _salary ;
} ;
and, secondly, the Manager class:
class Manager : public Employee {
public:
// Constructors
Manager(const char* name, double salary, set<Employee*>& subordinates) :
_name(name), _salary(salary), _subs(subordinates) {}
...
// Accessors
const char* name() const {
string name;
name += _name;
name += " (Manager)";
return name.c_str() ;
}
void businessCard(ostream& os = cout) const {
Employee::businessCard();
}
private:
string _name ;
double _salary ;
} ;
The problem, as I think, is in the name() function, because if I write it explicitly, it appears on the card, though it is not inherited.
Could anyone help?
When you call Employee::businessCard(); it will call const char* name() const { return _name.c_str() ; } of Employee class. But earlier during the construction of the Manager object, you haven't passed name to the base class Employee, so it's not set in Employee class and you got it empty while printing.
So to make it work, it should be something like
Manager(const char* name, double salary, set<Employee*>& subordinates) : Employee(name,salary), _subs(subordinates)
and remove _name and _salary member variables from manager as it defeats the purpose of inheritance in this example.
I am new to C++. Can someone please let me know what is wrong with the following code segment -
class Person {
public:
const std::string& name;
Person(const std::string& s): name(s) {}
void dump(void) const {
cout << name << endl;
//cout << &name << endl;
}
};
std::map<std::string, std::shared_ptr<Person>> plist;
std::string namestr = "Hoo";
std::shared_ptr<Person> r1(std::make_shared<Person>("Dull"));
plist.insert({"Key1", r1});
auto u = plist.find("Key1");
shared_ptr<Person> v = u->second;
v->dump();
plist.erase(plist.find("Key1"));
My intention is to create a database of Person objects and I was trying to use shared_ptr for that.
v->dump() causes a segmentation fault. However, if I use the 'namestr' variable instead of the string literal "Dull" then the v->dump() appears to work correctly, i.e. the following -
std::shared_ptr<Person> r1(std::make_shared<Person>(namestr));
Also, the following way also seems to work even though I use a string literal in the intializer.
std::shared_ptr<Person> r1(new Person("Dull"));
Pointers to the mistake I am making would be much appreciated!
class Person {
public:
const std::string& name;
Person(const std::string& s): name(s) {}
void dump(void) const {
cout << name << endl;
//cout << &name << endl;
}
};
this is storing a reference to a string whose life time is not guaranteed. You should do
class Person {
public:
const std::string name;
Person(const std::string& s): name(s) {}
void dump(void) const {
cout << name << endl;
//cout << &name << endl;
}
};
You code fails because "Dull" created a temporary string that went out of scope immediately
here is my problem:
code:
file1.hpp:
namespace Output {
class Stringify{ // base class.....
protected:
size_t prec;
public:
std::stringstream out;
public:
Stringify(const size_t& _p = 5): prec(_p) {out.precision(prec);}
virtual ~Stringify(void){}
public:
std::string operator()(const XYZ& _v){
out.str("");
out << "{ " << _v.x() << ", " << _v.y() << ", " << _v.z() << " }";
return out.str();
}
std::string operator()(const XYZ& _v, const bool& _status){
out << "{ " << _v.x() << ", " << _v.y() << ", " << _v.z() << " }";
return out.str();
}
};
}
where XYZ is a vector object.
file2.hpp:
namespace NODE {
class Stringify: public Output::Stringify {
public:
Stringify2(const size_t& _p = 5): Output::Stringify(_p) {}
virtual ~Stringify2(void){}
public:
std::string operator()(const VERTEX& _obj){ return "What?";}
};
}
where VERTEX is another object with members values of type XYZ
main.cpp:
int main(int argc,char * argv[]){
XYZ v(1,2,3);
NODE::Stringify printer;
cout << printer(v) << endl;
return 0;
}
output is:
What?
when it should:
be {1,2,3}
Compilation is ok but,
As far as I know, NODE::Stringify is able to print {1,2,3}, because of, his base object
has inherit the method for XYZ argument, but it prints the Method with the arguments
of VERTEX (What?). virtual word is not neccesary, because I do not overwrite a method in
the base class.
As a information: I am compiling in MAC OS 10.8 with llvm-gcc-4.2
using Eigen 3.0 libs (typedef Eigen::vector3d XYZ)
Any idea?
Thanks in advance.
Your operator () in the derived class hides the operator () overloads from the base class (which you name Stringify in your example, but that's probably a typo, since the constructor and destructor are named (~)Stringify2).
You can fix this through a using declaration inside the derived class:
namespace NODE {
class Stringify2 : public Output::Stringify {
// ^
public:
using Output::Stringify::operator ();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// This should fix the problem
Stringify2(const size_t& _p = 5): Output::Stringify(_p) {}
virtual ~Stringify2(void){}
public:
std::string operator()(const VERTEX& _obj){ return "What?";}
};
}