How to inherit constructor from a non-direct-parent base class - c++

In the very bottom Word class definition, I wanted to be able to inherit Dict's constructor, the Dict(string f) one. However, I can't do that directly since it's not a direct inherit; it follows a tree and its last parent is the Element class.
How would I be able to let the compiler know to let Word class inherit from the base class's instructor(Dict), so that I can perform the Word test("test.txt"); instantiation in main?
#include <iostream>
#include <vector>
#include <sstream>
#include <string.h>
#include <fstream>
using namespace std;
class Dict {
public:
string line;
int wordcount;
string word;
vector <string> words;
Dict(string f) { // I want to let Word inherit this constructor
ifstream in(f.c_str());
if (in) {
while(in >> word)
{
words.push_back(word);
}
}
else
cout << "ERROR couldn't open file" << endl;
in.close();
}
};
class Element : public Dict {
public:
virtual void complete(const Dict &d) = 0;
virtual void check(const Dict &d) = 0;
virtual void show() const = 0;
};
class Word: public Element {
public:
Word(string f) : Dict(f) { }; // Not allowed (How to fix?)
void complete(const Dict &d) { };
};
};
int main()
{
//Word test("test.txt");
return 0;
}

The Element class must expose the ability to call the Dict constructor in question.
In C++98/03, this means that Element must define a constructor with exactly the same parameters which simply calls the Dict constructor, and then Word would use that Element constructor instead of the Dict constructor.
In C++11, you can use constructor inheritance to save lots of typing and prevent possible errors.

Your Element class should provide the following constructor to:
Element( string iString ) : Dict( iString ) {;}
You'll then be able to call the Element constructor from your Word class which will propagate the call up to Dict.

Related

Regarding default constructor an object initialization/usage in C++ OOP

I have recently started learning OOP in C++ and I started solving example tasks regarding it. I want to instantiate an object of the class CStudent after having created a default constructor for it. However the compiler cannot compile the code. I would like to ask why is that?
When you write inside your class:
CStudent();
CStudent(string name, string fn);
...you only declare two constructors, one default (taking no-argument) and one taking two strings.
After declaring them, you need to define them, the same way you defined the methods getName or getAverage:
// Outside of the declaration of the class
CStudent::CStudent() { }
// Use member initializer list if you can
CStudent::CStudent(std::string name, string fn) :
name(std::move(name)), fn(std::move(fn)) { }
In C++, you can also define these when declaring them inside the class:
class CStudent {
// ...
public:
CStudent() { }
CStudent(std::string name, string fn) :
name(std::move(name)), fn(std::move(fn)) { }
// ...
};
Since C++11, you can let the compiler generate the default constructor for you:
// Inside the class declaration
CStudent() = default;
This should work, As commented by Holt, You need to define constructor, You have just declared it.
#include <iostream>
#include <string>
#include <list>
using namespace std;
class CStudent {
string name = "Steve";
list<int> scores;
string fn;
public:
CStudent() {};
CStudent(string name, string fn);
string getName();
double getAverage();
void addScore(int);
};
string CStudent::getName() {
return name;
}
double CStudent::getAverage() {
int av = 0;
for (auto x = scores.begin(); x != scores.end(); x++) {
av += *x;
}
return av / scores.size();
}
void CStudent::addScore(int sc) {
scores.push_back(sc);
}
int main()
{
CStudent stud1;
cout<< stud1.getName()<< endl;
return 0;
}

Compare the object type of a class that inherits from a parent class but stored in vector of parent class

I want to compare the object type of a child class which inherits from a parent class and is stored in a vector of parent class as below:
#include <string>
#include <iostream>
#include <vector>
#include <typeinfo>
using namespace std;
class Agent{
public:
Agent(string nam){ name = nam; }
~Agent();
protected:
string name;
};
class Human :public Agent{
public:
Human(string nam, int a):Agent(nam){ age = a; }
~Human();
protected:
int age;
};
int main(){
vector<Agent*> agents;
Agent* agent=new Agent("ask");
Human* human=new Human("ask2",18);
Agent* agent2=new Human("AgentAsk",20);
agents.push_back(agent);
agents.push_back(human);
agents.push_back(agent2);
cout << (typeid(agents[1]) == typeid(Agent*)) << endl; /// True
cout << (typeid(agents[1]) == typeid(Human*)) << endl; /// I expect it to be true but its false
cout << (typeid(agents[1]) != typeid(Agent*)) << endl; /// False
return 0;
}
I need help to obtain the proper result.
I searched for it but could not find a proper solution and explanation.
Please, try to explain your code as much as possible.
You can use type traits for your classes, but if you need a simple (quick and dirty, maybe) solution, you may do it as follows:
#include <string>
#include <iostream>
#include <vector>
#include <typeinfo>
using namespace std;
class Agent{
public:
static const string TYPE;
explicit Agent(const string& nam) : name(nam) {}
virtual ~Agent(){}
virtual string type() const {
return TYPE;
}
protected:
string name;
};
const string Agent::TYPE = "Agent";
class Human :public Agent {
public:
static const string TYPE;
Human(const string& nam, int a):Agent(nam), age(a) {}
~Human(){}
virtual string type() const {
return TYPE;
}
protected:
int age;
};
const string Human::TYPE = "Human";
int main(){
vector<Agent*> agents;
Agent* agent=new Agent("ask");
Human* human=new Human("ask2",18);
Agent* agent2=new Human("AgentAsk",20);
agents.push_back(agent);
agents.push_back(human);
agents.push_back(agent2);
for(auto agent : agents) {
cout << agent->type() << " ";
cout << boolalpha << (agent->type() == Agent::TYPE) << endl;
}
//free up memory allocated using new
// or just use smart pointers
return 0;
}
It's better to define an abstract class and move the abstraction (like type() method) up and other details down to the derived classes.
Here is a possible approach to differentiate the types in a hierarchy at runtime (comments in the code, as requested by the OP):
#include<vector>
#include<cassert>
// This is a simple class that acts as a counter
struct Cnt {
static int cnt;
};
int Cnt::cnt = 0;
// A template class helps us to differentiate
// the types and to give them a set of values
// that identify the actual types at runtime
template<typename T>
struct Type: private Cnt {
static const int type;
};
template<typename T>
const int Type<T>::type = Cnt::cnt++;
// The Agent offers a virtual method that
// returns a numeric identifier of the type.
// The above mentioned classes are used
// to generate an unique value for this type.
class Agent {
public:
virtual int type() const {
return Type<Agent>::type;
}
};
// If you want Human to have its own
// numeric identifier, you can simply override
// the inherited method and return a different
// type.
// Using the Type class is still the right
// solution. It assures that the returned type
// won't collide with the ones generated so
// far.
class Human: public Agent {
public:
int type() const override {
return Type<Human>::type;
}
};
int main() {
std::vector<Agent*> vec;
vec.push_back(new Agent);
vec.push_back(new Human);
assert(vec[0]->type() == Type<Agent>::type);
assert(vec[0]->type() != Type<Human>::type);
assert(vec[1]->type() == Type<Human>::type);
assert(vec[1]->type() != Type<Agent>::type);
}
It's pretty invasive, but this way you can also decide not to give a different type to a child if you want.
A note on typeid.
From here you can find that:
There is no guarantee that the sameĀ std::type_info instance will be referred to by all evaluations of the typeid expression on the same type
You wouldn't have had guarantees even if working with different types. Anyway, you are using the typeof operator each time on the same type.
You created a vector of Agent*, so (typeid(agents[1]) == typeid(Human*)) is false because agents[1] is an Agent, not a Human.

a function instead of copy-and-paste programming

I have an object, every member variable in this object has a name which I can acquire it by calling get_name() ,what I want to do is concatenate all the names of the member variables in alphabetical order, then do something. for example:
class CXMLWrapper<class T>
{
public:
CXMLWrapper(const char* p_name) : m_local_name(p_name)
{
}
//skip the get_name(), set_name() and others
private:
string m_local_name;
T m_type_var;
}
class object
{
public:
object() : m_team("team"), m_base("base")
{
}
public:
CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;
...
}
I have to hard-code like this:
object o;
string sign = o.m_base.get_name();
sign += o.m_team.get_name();
I need a function to do this instead of copying and pasting when the object varies. Anyone has an idea?
One way to do this in normal C++, provided all of the members belong to the same class or are derived from some base class will be to use variable number of arguments to a function. An example follows.
#include <stdarg.h>
string concatenateNames(int numMembers, ...)
{
string output;
va_list args;
va_start(args, numMembers);
for(int i = 0; i < numMembers; i++)
{
MemberClass *pMember = va_arg(args, MemberClass*);
output += pMember->get_name();
}
va_end(args);
return output;
}
class Object
{
public:
MemberClass x;
MemberClass y;
MemberClass z;
};
int main()
{
Object o;
string sign = concatenateNames(3, &o.x, &o.y, &o.z);
}
If the types of all the members are different, you can look into variadic templates of C++11x: http://en.wikipedia.org/wiki/Variadic_Templates, but I can't seem to find a way to do otherwise.
If variables which have name have a same type (or these types belongs one hierarchy) you can use map of these vars. Is not good way, but maybe it helps you
Example
class object
{
public:
object() //: m_team("team"), m_base("base")
{
this->vars["m_team"] = CXMLWrapper<string>("team");
//.....
}
public:
map<string, CXMLWrapper<string> > vars;
/*CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;*/
...
}
object o;
string sign;
for(auto& x : o.vars)//i cannot remember syntax of for of map
sign += x.get_name;
PS Sorry for my writing mistakes. English in not my native language.
One method is to have an external library of member names which the CXMLWrapper class updates:-
class BaseXMLWrapper
{
public:
void ListMembers (const char *parent)
{
// find "parent" in m_types
// if found, output members of vector
// else output "type not found"
}
protected:
void RegisterInstance (const char *parent, const char *member)
{
// find 'parent' in m_types
// if not found, create a new vector and add it to m_types
// find 'member' in parent vector
// if not found, add it
}
private:
static std::map <const std::string, std::vector <const std::string> >
m_types;
};
class CXMLWrapper <class T, const char *parent> : BaseXMLWrapper
{
public:
CXMLWrapper(const char* p_name) : m_local_name(p_name)
{
RegisterInstance (parent, p_name);
}
// you could override assignments, copy and move constructors to not call RegisterInstance
//skip the get_name() set_name()
private:
m_local_name;
}
class object
{
public:
object() : m_team("team"), m_base("base")
{
}
public:
CXMLWrapper<string, "object"> m_team;
CXMLWrapper<string, "object"> m_base;
...
};
This does add overhead to the construction of objects, but as it's only a constructor overhead it might not affect overall system performance much.
This looks like a "observe pattern", you just need to keep a single copy in object as a member variable "string name_;", and pass the name_s's reference into CXMLWrapper like this:
class CXMLWrapper<class T>
{
public:
CXMLWrapper(const string &name)
: local_name_(name)
{
}
//skip the get_name() set_name()
private:
const string &local_name_;
}
class object
{
public:
object()
: team_("team"),
base_("base"),
m_team(team_)
, m_base(base_)
{
}
public:
string team_;
string base_;
CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;
}

C++ Understanding Classes and Constructors

I am new to C++ (coming from Java). I am having trouble with putting together classes in C++.
My goal in this program is to simply implement a basic Animal class with a few strings and counter.
I want to be able to read in from a text file that I have created and set the lines in the text file to each of the these variables.
Species
Family
Phylum
Descendants
I then want the program to print out the results of all 3 classes.
I don't understand how to implement a default constructor.
Here is my class.
#include <iostream>
#include <string>
using namespace std;
class Animal
{
string species;
string family;
string phylum;
string desc;
static int count;
public:
bool readIn(ifstream&file, const string frame);
void printInfo() const;
void setAnimal(string s, string f, string p, string d);
static int getCount();
Animal(string s, string f, string p, string d);
Animal(ifstream& file, const string fname);
};
These are the function definitions:
#include "animal.h"
#include <iostream>
#include <string>
using namespace std;
Animal::Animal(string s, string f, string p, string d)
{
setAnimal(s,f,p,d);
}
static int Animal::getCount()
{
int i=0;
i++;
return i;
}
bool Animal::readIn(ifstream &myFile, const string fname)
{
myFile.open(fname);
if(myFile)
{
getline(myFile, species);
getline(myFile, family);
getline(myFile, phylum);
getline(myFile, desc);
myFile.close();
return true;
}
else
return false;
}
Animal::Animal(ifstream& file, const string fname)
{
if(!readIn(file, fname) )
species="ape";
family="ape";
phylum="ape";
desc="ape";
count = 1;
}
void Animal::printInfo() const
{
cout << species << endl;
cout << family << endl;
cout << phylum << endl;
cout << desc << endl;
}
void Animal::setAnimal(string s, string f, string p, string d)
{
species = s, family = f, phylum = p, desc = d;
}
int main()
{
ifstream myFile;
Animal a;
Animal b("homo sapien", "primate", "chordata", "erectus");
Animal c(myFile, "horse.txt");
a.printInfo();
b.printInfo();
c.printInfo();
}
A default constructor is one which can be called with no parameters specified. This description might seem a little verbose, so consider a couple possibilities.
Typically, or maybe by default (no pun), a default constructor will simply be a constructor which takes no parameters:
class Animal
{
public:
Animal() {}; // This is a default constructor
};
Other times though you might write a construcutor that does take parameters, but all the parameters have defaults:
class Animal
{
public:
Animal(int age=42) : age_(age) {}; // This is a default constructor
private:
int age_;
};
This is also a default constructor because it can be called with no parameters:
Animal a; // OK
You will not want to have 2 default constructors in a class. That is, don't try to write a class like this:
class Animal
{
public:
Animal() {};
Animal(int age=42) : age_(age) {};
private:
int age_;
};
In C++, if you have a class that has no default constructor, the compiler will generate one for you automatically. However, the compiler doesn't automatically generate a default constructor if you have already declared any other constructor yourself. So in your case, since you have already declared 2 other constructors (both are "convert" constructors), the compiler won't generate a default constructor for you. Since your class, as defined, doesn't have a default constructor, you can't default construct Animal objects. In other words, this won't compile:
Animal a;
A default constructor is simply a constructor that takes no parameters. The compiler generates one for you if you don't define any constructors of your own.
This auto generated one does nothing other than call the no-param constructors of the class' bases and members.
You can define a no-param constructor yourself.
To implement a default constructor, just do what you've already done but provide no parameters:
static int getCount();
Animal(string s, string f, string p, string d);
Animal(ifstream& file, const string fname);
Animal(); //Default Constructor
Then in your implementation:
Animal::Animal(){
species="ape";
family="ape";
phylum="ape";
desc="ape";
count = 1;
}

How to pass value to the object constructor's declare using dynamic memory allocation

The code is as follow :
The Code :
#include <iostream>
using namespace std;
class pub
{
string name;
public:
pub(string name):name(name){} //Constructor
void getName(string name){this->name = name;}
string returnName(void){return name;}
};
int main(void)
{
pub * p = new pub[5]; //Error-prone statement.
//Ignore for not having "delete" statement
return 0;
}
The Question :
1.) In this case , is there any method for me to pass value to each dynamic memory I've allocated , or is it I have to set a default value to the constructor's argument in order to circumvent this problem ?
Thank you !
If your compiler supports C++11 you could use std::vector and with an initializer list:
std::vector<pub> v { pub("1"), pub("2") };
See online demo https://ideone.com/Qp4uo .
Or std::array:
std::array<pub, 2> v = { { pub("1"), pub("2") } };
See online demo https://ideone.com/lBXUS .
Either of these also removes the burden of delete[]ing the dynamically allocated array.
Apart from the somewhat unconvential naming convention that you used (I changed getName() to setName() and returnName() to getName(), and used trailing _ to denote private data members), using a `std::vector will do the memory management automatically for you:
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class pub
{
public:
pub(): name_("default") {}
pub(string const& name): name_(name){} //Constructor
pub(const char* name): name_(name) {}
void setName(string const& name){ name_ = name;}
string getName(void) const {return name_;}
private:
string name_;
};
int main(void)
{
// initialize with 2 elements, then add 3 more default elements
std::vector<pub> pub_vec { "bla", "bar" };
pub_vec.resize(5);
std::for_each(pub_vec.begin(), pub_vec.end(), [](pub const& elem){
std::cout << elem.getName() << "\n";
});
return 0;
} // 5 destructors automatically called
Note: adding an overloaded constructor that takes const char* allows you to use string literals to initialize your data.
Output on Ideone
Use std::vector<pub>. It doesn't require the default constructor.
E.g.
std::vector<pub> vec(5, pub("xyz"));
creates a vector with 5 equal elements.