I am using this code
#include <iostream>
class person
{
class address
{
public:
std::string addr;
int pobox;
address()
{
addr = "Some Address";
pobox = 200;
}
};
address a;;
void Test()
{
std::cout << a.addr; //ERROR
}
};
int main()
{
}
I get this error
Error 1 error C2679: binary '<<' : no operator found which takes a
right-hand operand of type 'std::string' (or there is no acceptable
conversion)
Any suggestions on how i can fix it ?
You may want to do an include for string:
#include <string>
Besides including the <string> header as mentioned, I think the rest needs to be fixed, like follows:
#include <iostream>
#include <string>
class person {
class address {
public: // <<<<<<<<<<<<<<<
std::string addr;
int pobox;
address() {
addr = "Some Address";
pobox = 200;
}
};
address a;
public: // <<<<<<<<<<<<<<<
void Test() {
std::cout << a.addr;
}
};
int main() {
person p;
p.Test();
return 0;
}
See the Live Demo.
You'll need to make the class members in question publicly visible, to instantiate or call them.
You may declare address as a nested type of person (at least public to become useful), though I'm not so sure that this is such a good idea.
The much better approach seems to be declaring a own, self contained address class outside of person, and have the latter one contain a member for it:
class address {
public:
address() : addr_("Some Address"), pobox_(200) {}
const std::string& addr() const { return addr_; }
void addr(std::string value) { addr_ = value; }
int pobox() const { return pobox_; }
void pobox(int value ) { pobox_ = value; }
private:
std::string addr_;
int pobox_;
};
class person {
address a_;
public:
void Test() {
std::cout << "Address: " << a_.addr() << std::endl;
std::cout << "PO Box : " << a_.pobox() << std::endl;
}
};
int main() {
person p;
p.Test();
return 0;
}
See another Live Demo.
Related
I'm still learning how the abstract classes work and I want know if I'm on the right track or not.
This is my simplified program :
class CPerson
{
public:
CPerson() = default;
virtual int getMat() = 0;
};
class CStudent : public CPerson
{
public:
CStudent() = default;
CStudent(int MatriculationNr) { this->MatriculationNr = MatriculationNr;}
int getMat() { return MatriculationNr;}
private:
int MatriculationNr;
};
class CTeacher : public CPerson
{
public:
CTeacher() = default;
int getMat(){ return 0;}
private:
std::string name;
};
int main()
{
std::vector<CPerson*> test;
test.push_back(new CStudent(9898));
CTeacher *a = new CTeacher();
return 0;
}
In class CTeacher, I don't have the same private variable like CStudent (MatriculationNr) so I returned 0. The program is working normally. But is what I'm doing here correct or not?
Another question related to the abstract classes : Assuming we use virtual int& getMat() = 0; (with a reference), what should we return in CTeacher class? 0 will not work in this case, right?
Should we initalize a variable with 0 so that we can return it in this function, or is there a better implementation?
Below code sample should answer your question in a rather modern C++ way.
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// I have added a `std::string name` to the CPerson class and
// a `std::string subject` to the CTeachers class
// so both derived classes, CStudent and CTeacher have a name
// of the person involved and each derived class has
// something only it needs, MatrikulationNr for CStudent and
// Subject of teaching for CTeacher in order to deliver a more
// complete and more clearifying answer.
class CPerson {
int dummyMatriculationNr{ 0 };
std::string dummySubject{ "noTeacher" };
protected:
std::string name;
public:
std::string getName() { return name; }
virtual int& getMat() { return dummyMatriculationNr; }
virtual std::string getSubject() { return dummySubject; }
};
class CStudent : public CPerson {
int MatriculationNr{ 0 };
public:
CStudent() = delete; // we dont want anyone using this constructor
explicit CStudent(std::string name, int MatriculationNr) :
MatriculationNr{ MatriculationNr } {
this->name = name;
}
int& getMat() { return MatriculationNr; }
};
class CTeacher : public CPerson {
std::string subject{ "" }; // Subject of teaching
public:
CTeacher() = delete;
explicit CTeacher(std::string name, std::string subject) :
subject{ subject } {
this->name = name;
}
std::string getSubject() { return subject; }
};
int main() {
std::vector<std::unique_ptr<CPerson>> vp;
vp.push_back(std::make_unique<CStudent>("aStudentsName", 8989 ));// or emplace_back
vp.push_back(std::make_unique<CTeacher>("aTeachersName", "mathematics"));
for (auto& e : vp)
std::cout << "Name: " << e->getName() << " MatrNo: " << e->getMat()
<< " TeachingSubject: " << e->getSubject() << std::endl;
}
I hope above sample answers your question. However, using the keyword virtual creates a virtual function table, often called vtable, at runtime which costs performance and is considered not to be high performance computing anymore.
Its also confusing to have a getMat() function available in all derived classes when you need it only in one, the CStudents derived class. Although meaningless in any other class, this function still returns some dummy value there. That can be irritating. Same for the getSubject() function in CTeacher. See the output:
Name: aStudentsName MatrNo: 8989 TeachingSubject: noTeacher
Name: aTeachersName MatrNo: 0 TeachingSubject: mathematics
Consider to solve your question without any keyword virtual and having getMat() and int MatriculationNr in CStudents only and not in the base class at all. I know it is tempting to use virtual but its something to rather avoid as long as possible. For example, MFC, Microsoft Foundation Classes, the maybe biggest class inheritance project ever written, did not use virtual at all!
Consider the following code as an example:
#include <iostream>
#include <string>
#include <vector>
#include <variant>
// a code version without virtual
class CPerson {
protected:
std::string name;
public:
std::string getName() { return name; }
};
class CStudent : public CPerson {
int MatriculationNr{ 0 };
public:
CStudent() = delete; // we dont want anyone using this constructor
explicit CStudent(std::string name, int MatriculationNr) : MatriculationNr{ MatriculationNr } {
this->name = name;
}
int& getMat() { return MatriculationNr; }
};
class CTeacher : public CPerson {
std::string subject{ "" }; // Subject of teaching
public:
CTeacher() = delete;
explicit CTeacher(std::string name, std::string subject) : subject{ subject } {
this->name = name;
}
std::string getSubject() { return subject; }
};
int main() {
std::vector<CStudent> vs; // auto-deleted through RAII
std::vector<CTeacher> vt; // and good for serialisation and or database communication
vs.push_back(CStudent{ "aStudentsName", 9898 });
vt.push_back(CTeacher{ "aTeachersName", "mathematics" });
for (auto s : vs)
std::cout << s.getName() << " " << s.getMat() << std::endl;
for (auto t : vt)
std::cout << t.getName() << " " << t.getSubject() << std::endl << std::endl;
// and here we are done already,
// not listing the two different types in one vector
// but just using a vector for each derived class
//
// but lets try put them now into one vector
// using a more modern way through std::variant
// which keps all data in the vector and not only the
// CPerson part.
std::vector<std::variant<CStudent, CTeacher>> people;
// we could, for example, copy from above vectors
for (auto e : vs)
people.push_back(e);
for (auto e : vt)
people.push_back(e);
// we could insert new ones
people.push_back(CStudent { "aStudentsName1", 9899 });
people.push_back(CTeacher { "aTeachersName1", "physics" });
// and take that vector apart again
std::cout << std::endl << "Output from vector of variant:" << std::endl;
for (auto& e : people)
if (std::holds_alternative<CStudent>(e)) {
CStudent& s = std::get<CStudent>(e);
std::cout << s.getName() << " " << s.getMat() << std::endl;
}
else if (std::holds_alternative<CTeacher>(e)) {
CTeacher& s = std::get<CTeacher>(e);
std::cout << s.getName() << " " << s.getSubject() << std::endl;
}
}
There are numerous ways to achieve the goal to avoid virtual and I hope you did enjoy the above.
Everything in the code above seems alright. Just make sure to delete both objects after using them (the CStudent and the CTeacher).
Today I'm working on a singleton test case in c++.
The singleton is working fine but I would like to instantiate the static object when the user try to access a member of it, so if the variable isn't created when we try to access a member of it, it will not crash instead it will simply generate my singleton.
Here's my class.h:
class PDG : public EmployeRH
{
public:
static void Instantiate(std::string nom, std::string prenom);
// Current manual instantiation version of the singleton
PDG* operator->();
// This is the line I just added to overload "->" operator ... But it seems it's never called.
void SePresenter();
static PDG* _instance;
private:
PDG();
~PDG();
PDG(std::string nom, std::string prenom);
int _budget;
};
Methods.cpp
PDG* PDG::_instance=NULL;
PDG::PDG()
{
}
PDG::~PDG()
{
}
PDG::PDG(std::string a_nom, std::string a_prenom):EmployeRH(a_nom,a_prenom)
{
_budget = 100000;
}
void PDG::Instantiate(std::string a_nom, std::string a_prenom)
{
cout << "instantiation pdg" << endl;
if (_instance == NULL)
{
_instance = new PDG(a_nom,a_prenom);
}
}
PDG* PDG::operator->()
{
PDG::Instantiate("Unknown", "Unknown");
return _instance;
}
void PDG::SePresenter()
{
cout << _nom << " " << _prenom << endl;
}
main.cpp
void main()
{
PDG::_instance->SePresenter();
system("pause");
}
The thing is, it goes directly into "SePresenter()" and not into my overloaded operator "->".
If anyone could help it would be greatfull.
Thanks,
Impact
PDG::_instance is a pointer to PDG so -> simply dereferences the pointer and you can't override the behaviour. To override the -> operator you must call it on the class directly not on a pointer: (*PDG::_instance)->SePresenter(). To preserve your desired syntax and to remove the undefined behaviour from dereferencing the null pointer you can change PDG::_instance into a structure which holds your instance pointer.
#include <string>
#include <iostream>
using namespace std;
struct EmployeRH {
EmployeRH() {}
EmployeRH(std::string nom, std::string prenom) {}
std::string _nom;
std::string _prenom;
};
class PDG : public EmployeRH {
public:
static PDG* Instantiate(std::string nom, std::string prenom);
// Current manual instantiation version of the singleton
void SePresenter();
static struct Instance {
PDG* operator->()
{
return PDG::Instantiate("Unknown", "Unknown");
}
} _instance;
private:
PDG();
~PDG();
PDG(std::string nom, std::string prenom);
int _budget;
};
PDG::Instance PDG::_instance;
PDG::PDG()
{
}
PDG::~PDG()
{
}
PDG::PDG(std::string a_nom, std::string a_prenom)
: EmployeRH(a_nom, a_prenom)
{
_budget = 100000;
}
PDG* PDG::Instantiate(std::string a_nom, std::string a_prenom)
{
static PDG instance(a_nom, a_prenom);
cout << "instantiation pdg" << endl;
return &instance;
}
void PDG::SePresenter()
{
cout << _nom << " " << _prenom << endl;
}
int main()
{
PDG::_instance->SePresenter();
return 0;
}
I've also changed your singleton to use a function static which makes your code thread safe.
In the following code, a non-const method of an object calls a const-method of the same object that returns a const-pointer to the object's field, and then this returned pointer is casted to a non-const version — it's a technique similar to one in this answer: Elegant solution to duplicate, const and non-const, getters? [duplicate]. However, since I put pointers into a complex data structure, I am not sure it will actually work. Will it?
class Struct {
private:
Field f, g;
std::map<std::string, const FieldBase*> const_fields_t;
std::map<std::string, FieldBase*> fields_t;
public:
const_fields_t get_fields() const {
return const_fields_t { { "f", &f }, { "g", &g } };
}
fields_t get_fields() {
const Foo* = this;
fields_t result;
foreach(auto& v : const_this->get_fields()) {
result[v->first] = const_cast<FieldBase*>(v->second);
}
return result;
}
};
Yes, (I cleaned up your code a bit):
#include <string>
#include <functional>
#include <iostream>
#include <map>
using namespace std;
class FieldBase {public: virtual string get_data() = 0; };
class Field : public FieldBase { public: string data; virtual string get_data() { return data; } };
class Struct {
public:
Field f, g;
typedef std::map<std::string, const FieldBase*> const_fields_t;
typedef std::map<std::string, FieldBase*> fields_t;
public:
const_fields_t get_fields() const {
cout << "const get_fields() called" << endl;
return const_fields_t { { "f", &f }, { "g", &g } };
}
fields_t get_fields() {
cout << "non-const get_fields() called" << endl;
auto const_this = static_cast<const Struct*>(this);
fields_t result;
for(auto& v : const_this->get_fields()) {
result[v.first] = const_cast<FieldBase*>(v.second);
}
return result;
}
};
int main ()
{
Struct a;
a.f.data = "Hello";
a.g.data = "World";
Struct::fields_t obj = a.get_fields();
cout << obj["f"]->get_data() << endl;
cout << obj["g"]->get_data() << endl;
}
Live example
You basically have the const function act like a gateway to get the values you need and then cast away the constness. That will also work for your purpose since the pointers are going to be de-consted and stored in the new map.
Keep in mind that there might probably be a better solution not involving all the above copying around.
I have a templated class Parameter which can (or must) be specialized.
I want to put all my parameters in a container.
How to do this if my parameters are instanciated with different types?
In the class Container, I would like to have a vector<Parameter*> from different types (int, double, ...) or something equivalent which seems to not possible.
If the Parameter class is derived from a base class, then The Container can declare the vect as vector<Base*>. But in this case, we can do nothing specific in Container::foo.
Below is my source example. One of my parameters is a QString which is not compatible with ostream.
Thanks for your comments.
#include <QString>
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
#define P(a) cout << #a << ":" << a << endl
/*
class Base {
};
*/
template<typename T> class Parameter /*: public Base */ {
private:
T val;
public:
void setVal(const T &val) {
this->val = val;
}
const T &getVal() {
return val;
}
string getFoo() {
stringstream s;
s << val;
return s.str();
}
};
template<>
string Parameter<QString>::getFoo() {
stringstream s;
s << val.toStdString();
return s.str();
}
class Container {
public:
void push_back(Parameter *base) {
vect.push_back(base);
}
void foo() {
/* do something with the parameters */
}
private:
vector<Parameter*> vect;
};
int main() {
Parameter<int> pi;
Parameter<QString> ps;
pi.setVal(10);
ps.setVal("QString");
P(pi.getVal());
P(ps.getVal().toStdString());
P(pi.getFoo());
P(ps.getFoo());
Container container;
container.push_back(&pi);
container.push_back(&ps);
}
Many thanks to you comments. I will follow your advice and use boost::any.
Here is the updated version :
#include <boost/any.hpp>
#include <QString>
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
#define P(a) cout << #a << ":" << a << endl
template<typename T> class Parameter {
private:
T val;
public:
void setVal(const T &val) {
this->val = val;
}
const T &getVal() {
return val;
}
string getFoo() {
stringstream s;
s << val;
return s.str();
}
};
template<>
string Parameter<QString>::getFoo() {
stringstream s;
s << val.toStdString();
return s.str();
}
class Container {
public:
void push_back(boost::any base) {
vect.push_back(base);
}
void foo() {
cout << "do something with the parameters\n";
for (vector<boost::any>::iterator i = vect.begin(); i != vect.end(); ++i) {
boost::any a = (*i);
if (a.type() == typeid(Parameter<int>*)) {
Parameter<int> *ai = boost::any_cast<Parameter<int> *>(a);
cout << ai->getFoo() << endl;
} else if (a.type() == typeid(Parameter<QString>*)) {
Parameter<QString> *aq = boost::any_cast<Parameter<QString> *>(a);
cout << aq->getFoo() << endl;
} else {
cout << "unknown type:" << a.type().name() << endl;
}
}
}
private:
vector<boost::any> vect;
};
int main() {
Parameter<int> pi;
Parameter<QString> ps;
pi.setVal(10);
ps.setVal("QString");
P(pi.getVal());
P(ps.getVal().toStdString());
P(pi.getFoo());
P(ps.getFoo());
Container container;
container.push_back(&pi);
container.push_back(&ps);
container.foo();
}
The correct solution is to write good enough interface for the Base class so that you can do everything you need to do:
class Base {
public:
virtual void *GetVal() const=0;
virtual void SetVal(void *ptr)=0;
virtual std::string Type() const=0;
virtual std::string GetAsString() const=0;
};
While this might not be what you want, it still allows passing values from one parameter to the next. Once you want the actual value, you do need to know the type on compile-time. Switch-case for the type might help with making it runtime.
You could use Boost.Any which can hold any type of data. You would then use boost::any_cast<> to convert the object back to the correct type.
Other than that, you'll have to go for the base class approach, but as you mentioned, it could be hard to then make Container::foo do anything useful.
One way you could solve this problem is to have all your foo functions take a string as a parameter, then each specific implementation of the function would parse that string and convert it to the correct type.
Edit: Boost.Any example:
#include <iostream>
#include <boost/any.hpp>
int main()
{
boost::any param = 89;
// This will fail because `param` is currently holding an int
// not a char
char ch = boost::any_cast<char>(param);
// This works
int i = boost::any_cast<int>(param);
// You can always change the value and type of what
// `param` is holding
param = "example";
}
Every thing inside a container has to be the same type. I have done something similar to your approach where I made a base class that had some useful generic interface and the derived class was templated. The only other way to approach a solution would involve defining a base class function to return a value to indicate the type and then downcasting the base.
Say I have the following classes in C++, and I want to inspect their inheritance:
Vehicle
Motorcar is a Vehicle
Aircraft is a Vehicle
Biplane is an Aircraft is a Vehicle
Helicopter is an Aircraft is a Vehicle.
I want to write a method getClassLineage() to do the following:
Biplane b;
cout << b.getClassLineage() << endl; // prints "Vehicle--Aircraft--Biplane"
Helicopter h;
cout << h.getClassLineage() << endl; // prints "Vehicle--Aircraft--Helicopter"
Motorcar m;
cout << m.getClassLineage() << endl; // prints "Vehicle--Motorcar"
It seems like there should be a simple recursive way to do this by writing it once in the super-class, without duplicating an essentially identical method in every single one of the derived classes.
Assume we're willing to declare (pseudocode)Helicopter.className = "Helicopter" and
typedef Aircraft baseclass in each of the derived classes, but trying to avoid copying and pasting getClassLineage().
Is there an elegant way to write this?
(Thank you for your thoughts!)
Solution 1
IF you're okay with the decorated name, then you can write a free function template:
struct Vehicle {};
struct Aircraft : Vehicle { typedef Vehicle super; };
struct Helicopter : Aircraft { typedef Aircraft super; };
template<typename T>
string getClassLineage()
{
static string lineage = string(typeid(T).name()) +" - " + getClassLineage<typename T::super>();
return lineage;
}
template<>
string getClassLineage<Vehicle>()
{
static string lineage = string(typeid(Vehicle).name());
return lineage;
}
int main() {
cout << getClassLineage<Helicopter>() << endl;
return 0;
}
Output (decorated names):
10Helicopter - 8Aircraft - 7Vehicle
See at ideone: http://www.ideone.com/5PoJ0
You can strip off the decoration if you want. But it would be compiler specific! Here is a version that makes use of remove_decoration function to strip off the decoration, and then the output becomes :
Helicopter - Aircraft - Vehicle
By the way, as I said, the implementation of remove_decoration function is a compiler specific; also, this can be written in more correct way, as I don't know all cases which GCC considers, while mangling the class names. But I hope, you get the basic idea.
Solution 2
If you're okay with redefining the function in each derived class, then here is a simple solution:
struct Vehicle
{
string getClassLineage() const { return "Vehicle"; }
};
struct Aircraft : Vehicle
{
string getClassLineage() const { return Vehicle::getClassLineage()+" - Aircraft"; }
};
struct Helicopter : Aircraft
{
string getClassLineage() const { return Aircraft::getClassLineage()+" - Helicopter "; }
};
int main() {
Helicopter heli;
cout << heli.getClassLineage() << endl;
return 0;
}
Output:
Vehicle - Aircraft - Helicopter
See output at ideone: http://www.ideone.com/Z0Tws
If you want a recursive-like approach you can do it with virtual functions and explicit scoped function calls:
struct vehicle {
virtual std::string lineage() const { return "vehicle"; }
};
struct aircraft : vehicle {
typedef vehicle base;
virtual std::string lineage() const { return base::lineage() + "--aircraft"; }
};
struct biplane : aircraft {
typedef aircraft base;
virtual std::string lineage() const { return base::lineage() + "--biplane"; }
};
struct nieuport17 : biplane {
typedef biplane base;
virtual std::string lineage() const { return base::lineage() + "--nieuport17"; }
};
int main() {
biplane b;
aircraft const & a = b;
std::cout << a.lineage() << std::endl;
}
How does it work? When you call v.lineage() as it is a virtual function it the dynamic dispatch will make its way into biplane::lineage() as that is the actual type of the object. Inside that function there is a qualified call to its parent's lineage() function. Qualified calls do not use the dynamic dispatch mechanism, so the call will actually execute at the parents level. Basically this is what is going on:
a.lineage() -- dynamic dispatch -->
---> biplane::lineage()
\__ airplane::lineage()
\__ vehigcle::lineage()
<-- std::string("vehicle")
<-- std::string("vehicle") + "--airplane"
<-- std::string("vehicle--airplane") + "--biplane"
<--- std::string( "vehicle--airplane--biplane" )
[...]but trying to avoid copying and pasting getClassLineage().
As far as I know, that's not possible. C++ doesn't have reflection in and of itself, so the programmer has to do the work himself. The following C++0x version works under Visual Studio 2010, but I can't say for other compilers:
#include <string>
#include <typeinfo>
#include <iostream>
class Vehicle{
public:
virtual std::string GetLineage(){
return std::string(typeid(decltype(this)).name());
}
};
class Aircraft : public Vehicle{
public:
virtual std::string GetLineage(){
std::string lineage = std::string(typeid(decltype(this)).name());
lineage += " is derived from ";
lineage += Vehicle::GetLineage();
return lineage;
}
};
class Biplane : public Aircraft{
public:
virtual std::string GetLineage(){
std::string lineage = std::string(typeid(decltype(this)).name());
lineage += " is derived from ";
lineage += Aircraft::GetLineage();
return lineage;
}
};
class Helicopter : public Aircraft{
public:
virtual std::string GetLineage(){
std::string lineage = std::string(typeid(decltype(this)).name());
lineage += " is derived from ";
lineage += Aircraft::GetLineage();
return lineage;
}
};
int main(){
Vehicle v;
Aircraft a;
Biplane b;
Helicopter h;
std::cout << v.GetLineage() << std::endl;
std::cout << a.GetLineage() << std::endl;
std::cout << b.GetLineage() << std::endl;
std::cout << h.GetLineage() << std::endl;
std::cin.get();
return 0;
}
Output:
class Vehicle *
class Aircraft * is derived from class Vehicle *
class Biplane * is derived from class Aircraft *
class Helicopter * is derived from class Aircraft *
The output is slightly different at ideone, it drops the asterisk and decorates the name with a P at the beginning for pointer, but it works. Fun fact: trying to use typeid(decltype(*this)).name() crashed VS2010's compiler for me.
You need a static field to store the lineage, and each class will have its own lineage appended in its own static field.
If you are thinking about using typeid() or something like that, which is more complex but would avoid the repetition of the getClassLineage() method, remember that the name field attribute is annoyingly (the reason for this is beyond me) not the true name of the class, but a string that can be that name or any kind of mangled name (i.e., undefined representation).
You could easily apply a recursive aproach as the one you suggest if we were using Python or any other prototype-based programming language, in which inheritance is implemented by delegation, and thus the "inheritance path" can be followed.
#include <iostream>
#include <string>
class Vehicle {
public:
static const std::string Lineage;
Vehicle() {}
virtual ~Vehicle() {}
virtual const std::string &getClassLineage()
{ return Vehicle::Lineage; }
};
class Motorcar : public Vehicle {
public:
static const std::string Lineage;
Motorcar() {}
virtual ~Motorcar() {}
virtual const std::string &getClassLineage()
{ return Motorcar::Lineage; }
};
class Helicopter : public Vehicle {
public:
static const std::string Lineage;
Helicopter() {}
virtual ~Helicopter() {}
virtual const std::string &getClassLineage()
{ return Helicopter::Lineage; }
};
class Biplane : public Vehicle {
public:
static const std::string Lineage;
Biplane() {}
virtual ~Biplane() {}
virtual const std::string &getClassLineage()
{ return Biplane::Lineage; }
};
const std::string Vehicle::Lineage = "Vehicle";
const std::string Motorcar::Lineage = "Vehicle::Motorcar";
const std::string Helicopter::Lineage = "Vehicle::Helicopter";
const std::string Biplane::Lineage = "Vehicle::Biplane";
int main()
{
Biplane b;
std::cout << b.getClassLineage() << std::endl; // prints "Vehicle--Aircraft--Biplane"
Helicopter h;
std::cout << h.getClassLineage() << std::endl; // prints "Vehicle--Aircraft--Helicopter"
Motorcar m;
std::cout << m.getClassLineage() << std::endl; // prints "Vehicle--Motorcar"
return 0;
}
#include <iostream>
#include <ios>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <list>
#include <sstream>
using namespace std;
static const char *strVehicle = "Vehicle";
static const char *strMotorcar = "Motorcar";
static const char *strHelicopter = "Helicopter";
class Vehicle
{
private:
const char *ClassName;
protected:
int Lineage;
list<const char *> MasterList;
public:
Vehicle(const char *name = strVehicle)
{
MasterList.push_back(name);
}
virtual ~Vehicle() {}
virtual int getClassLineage() const
{
return Lineage;
}
string getName() const
{
list<const char *>::const_iterator it = MasterList.begin();
ostringstream ss( ios_base::in | ios_base::out );
while(it != MasterList.end())
{
ss << *(it++);
if(it != MasterList.end())
ss << " --> ";
}
ss << endl;
ss << ends;
return ss.str();
}
};
class Motorcar : public Vehicle
{
private:
const char *ClassName;
public:
Motorcar(const char *name = strMotorcar)
{
MasterList.push_back(name);
}
virtual ~Motorcar() {}
using Vehicle::getClassLineage;
using Vehicle::getName;
};
class Helicopter : public Vehicle
{
private:
const char *ClassName;
public:
Helicopter(const char *name = strHelicopter)
{
MasterList.push_back(name);
}
virtual ~Helicopter() {}
using Vehicle::getClassLineage;
using Vehicle::getName;
};
int _tmain(int argc, _TCHAR* argv[])
{
Helicopter h;
Motorcar m;
wcout << "Heli: " << h.getName().c_str() << endl;
wcout << "Motorcar: " << m.getName().c_str() << endl;
return 0;
}
If using typeid you don't need to hardcode strings (class' names). Solution for your problem could be:
#include <iostream>
#include <typeinfo>
using namespace std;
class Vehicle
{
public:
Vehicle();
string GetClassLineage(){return strName;}
protected:
string strName;
};
Vehicle::Vehicle() : strName(typeid(*this).name())
{
// trim "class "
strName = strName.substr(strName.find(" ") + 1);
}
class Motorcar : public Vehicle
{
public:
Motorcar();
};
Motorcar::Motorcar()
{
string strMyName(typeid(*this).name());
strMyName = strMyName.substr(strMyName.find(" ") + 1);
strName += " -- ";
strName += strMyName;
}
int main()
{
Motorcar motorcar;
cout << motorcar.GetClassLineage() << endl;
return 0;
}
Output:
Vehicle -- Motorcar