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;
}
Related
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;
}
I want to write a class (Class2) that uses another class (Class1).
Class1 requires 2 parameters (the 2nd parameter is always the same so no need to talk about it).
Class2 require 1 parameter, and I want to check this parameter if its valid before passing it to an object created from Class1
So my code looks like this :
class Class1
{
public:
Class1(const string & filename, some_other_parameters);
...
};
class Class2
{
Class1 C1;
public:
Class2(const string & filename) // I want to verify this filename before passing it to C1 object
};
Class2::Class2(const string & filename)
: C1(filename, some_other_parameters){
}
int main()
{
Class2 myClass("file.txt");
}
So is there a way to check the filename before passing it to C1 or should I do it in the main() ?
Just invoke a static function to do the validation, but otherwise forward it's argument:
class Class2
{
Class1 C1;
static const std::string& validate_filename(const std::string& filename);
public:
Class2(const string & filename)
};
const std::string& Class2::validate_filename(const std::string& filename)
{
if (filename.size() < 2)
throw std::runtime_error("filename too short");
return filename;
}
Class2::Class2(const string & filename)
: C1(validate_filename(filename), some_other_parameters){
}
Note that you can use a similar technique if you want to transform the argument. So you can convert from wide char to utf8 and force the path to be in a canonical format, ... and still have the member variable be const.
You should also consider which class should be responsible for the validation. If C1 has constraints on its arguments, then it should check them. If on the other hand it would be fine with any string, but C2 has constraints, then it must do the checking.
You can just used a pointer for Class1
#include "stdafx.h"
#include <string>
class Class1
{
public:
Class1(const std::string & filename, int a)
{
// ...
}
};
class Class2
{
Class1 * p_C1;
public:
Class2(const std::string & filename)
{
// ------------------------------------
// Check the file before p_C1 creation
// ------------------------------------
p_C1 = new Class1(filename, 1);
}
~Class2(void)
{
if (p_C1 != NULL) delete p_C1;
}
};
int main()
{
Class2 myClass("file.txt");
}
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;
}
My code compiles fine but I am having issues with a particular section not displaying the correct output.
Here is my base class
class Item
{
protected:
//int count;
string model_name;
int item_number;
public:
Item();
Item(string name, int number);
string getName(){return model_name;}
int getNumber(){return item_number;}
and here is my derived class:
class Bed : public Item
{
private:
string frame;
string frameColour;
string mattress;
public:
Bed();
Bed(int number, string name, string frm, string fclr, string mtres);
Function definitions:
Bed::Bed(int number, string name, string frm, string fclr, string mtres)
{
model_name=name;
item_number=number;
frame=frm;
frameColour=fclr;
mattress=mtres;
cout<<model_name<<item_number<<frame<<frameColour<<mattress<<endl;
}
Main section that is causing the problem:
Item* item= new Bed(number, name, material, colour, mattress);
cout<<"working, new bed"<<endl;
v.push_back(item);
cout<<"working pushback"<<endl;
cout<<" this is whats been stored:"<<endl;
cout<<v[count]->getName<<endl;
cout<<v[count]->getNumber<<endl;
count++;
when the programme executes, the cout within the constructor shows the correct output, but when I call getname and getnumber from the main function the programme prints '1' for both , no matter what's stored in there.
I thought that derived classes could use base class methods, what have I missed?
Any help would be great
thanks
Hx
Well, you example is not related to polymorphism. The reason here is that you are not using any virtual functions. Here is the code that you can use.
class Item
{
protected:
std::string model_name;
int item_number;
public:
Item();
Item(std::string& name, int number) : model_name(name), item_number(number) {};
std::string getName(){return model_name;}
int getNumber(){return item_number;}
};
class Bed : public Item
{
private:
std::string frame;
std::string frameColour;
std::string mattress;
public:
Bed();
Bed(int number, std::string& name, std::string& frm, std::string& fclr, std::string& mtres) : Item(name, number),
frame(frm),
frameColour(fclr),
mattress(mtres) {};
};
int main()
{
int count = 0;
std::vector<Item*> v;
Item* item = new Bed(2, std::string("MyBed"), std::string("wood"), std::string("red"), std::string("soft"));
std::cout << "working, new bed" << std::endl;
v.push_back(item);
std::cout << "working pushback" << std::endl;
std::cout << " this is whats been stored:" << std::endl;
std::cout << v[count]->getName() << std::endl;
std::cout << v[count]->getNumber() << std::endl;
++count;
getchar();
}
This looks incorrect (and I am unsure how this even compiled):
cout<<v[count]->getName<<endl;
cout<<v[count]->getNumber<<endl;
as getName and getNumber are methods. Change to:
cout<<v[count]->getName()<<endl;
cout<<v[count]->getNumber()<<endl;
Additionally, the initialisation of count is not posted: ensure it is zero.
count appears to be the size of your vector. After you push back the last element, you're not incrementing count, so you're printing an older element.
Why don't you try:
cout<<v[v.size()-1]->getName<<endl;
cout<<v[v.size()-1]->getNumber<<endl;
Also, you should start using initialization lists in your constructors:
Bed::Bed(int number, string name, string frm, string fclr, string mtres) :
Item(name,number),
frame(frm),
frameColour(fclr),
mattress(mtres)
{
}
You have not called the base class's constructor from the derived class... Where as it should be the first line... update the code, I am sure it will start working..
EDIT
If it doesn't than you should probably also check the way you are handling count variable... as pointed out by others..
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.