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

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;
}

Related

Avoid creating named variables when pointer is required

I have been creating named variables in order to be able to pass their adress to a constructor that expects a pointer, but I want to be able to create them in a constructor or other function and then pass their address to the constructor that expects a pointer.
I am using C++ 20 and I have the following classes:
#include <iostream>
#include <string>
#include <vector>
#include <random>
using std::string, std::cout, std::cin, std::endl, std::vector;
class symbol {
public:
enum symbolKind {
null,
terminal,
sequence,
weighted,
random
};
protected:
symbolKind kind;
public:
virtual string evaluate() const = 0;
symbolKind getKind() {
return kind;
}
};
class nullSymbol : public symbol {
public:
nullSymbol() {
kind = symbol::null;
}
string evaluate() const override {
return "";
}
};
class terminalSymbol : public symbol {
private:
string termString;
public:
terminalSymbol(string pString) {
kind = symbol::terminal;
termString = pPhoneme;
}
string evaluate() const override {
return termString;
}
};
class sequenceSymbol : public symbol {
private:
vector<symbol*> symArray;
public:
sequenceSymbol(vector<symbol*> pArr) {
kind = symbol::sequence;
symArray = pArr;
}
string evaluate() const override {
string retStr = "";
for (symbol* current : symArray) {
retStr += current->evaluate();
}
return retStr;
}
};
class weightedSymbol : public symbol {
private:
float weight;
symbol* subSym;
public:
weightedSymbol(symbol* pSym, float pWeight) {
kind = symbol::weighted;
subSym = pSym;
weight = pWeight;
}
string evaluate() const override {
return subSym->evaluate();
}
float getWeight() {
return weight;
}
};
class randomSymbol : public symbol {
private:
vector<weightedSymbol*> symArray;
public:
randomSymbol(vector<weightedSymbol*> pArr) {
kind = symbol::random;
symArray = pArr;
}
string evaluate() const override {
float sum = 0.0;
for (weightedSymbol* current : symArray) {
sum += current->getWeight();
}
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0.0, sum);
float randomResult = dis(gen);
float prev = 0;
for (weightedSymbol* current : symArray) {
if (randomResult < (prev += current->getWeight())) return current->evaluate();
}
}
};
I have been creating symbols like this:
terminalSymbol term_a("a");
terminalSymbol term_b("b");
sequenceSymbol seq_ab({ &term_a, &term_b});
cout << "ab test: " << seq_ab.evaluate() << endl;
But I would want to be able to do it like this or similar:
sequenceSymbol seq_ab_2({&terminalSymbol("a"), &terminalSymbol("b")});
cout << "ab test 2: " << seq_ab_2.evaluate() << endl;
This creates an error '&' requires l-value in Visual Studio.
This is a pretty simple example, often there are a lot more variables being created than this. In this case, the addresses are being passed to the std::vector<weightedSymbol*>() constructor; it's the same with the weightedSymbol() constructor which also expects a pointer. This should work not only for the constructor (it doesn't even need to work with the constructor itself if there is another way to achieve the same functionality), but I want a way to create heap objects in a function and then return a pointer to them that works in this situation. It might be that I need to change the classes themselves for this to work, they should just provide the same functionality.
In the end, I want to create these symbol objects dynamically based on user input.
I have searched online and tried using a bunch of different things but didn't manage to get the functionality I want working. What would be a good way to implement this? There is probably a common technique/idiom that I can use, if so, please explain it to me in detail so that I can use it in other projects too.
The objects you pass by pointers need to be destroyed somehow. In this snippet they will be destroyed automatically whenever you exit the block:
terminalSymbol term_a("a");
terminalSymbol term_b("b");
sequenceSymbol seq_ab({ &term_a, &term_b});
What should happen if you create objects without a named variable? Your classes never delete the objects that you pass by pointers, so that should be the caller responsibility to manage the lifespan of each object.
One solution for your problem is to wrap the objects into any sort of smart pointers. For example:
class sequenceSymbol : public symbol {
public:
sequenceSymbol(vector<shared_ptr<symbol>> pArr);
};
sequenceSymbol seq_ab_2({
std::make_shared<terminalSymbol>("a"),
std::make_shared<terminalSymbol>("b")
});

Class inside namespace and set function outside in C++

In this task i need to set and get number of soldiers outside of class and namespace (and call it in main properly)
namespace GeneralStaff
{
class Troops
{
private:
int nSoldiers;
public:
string name;
string rank;
Troops(string _name, string _rank, )
{
name= "Unknown";
rank= "RankUnknown";
}
};
} // namespace GeneralStaff
This is outside of class and function
void GeneralStaff::Troops setSoldierN(int n)
{
nSoldiers= n;
}
In main:
GeneralStaff::Troops;
Troops.setSoldierN(10);
I know that i need proper object declaration in main (source) and problem is with function set.
To define a method of the class outside the class, just use the scope resolution(::) operator. But for defining a function outside the class, you need to declare it in the class itself, which you have not done. Check the following code, it should work:
namespace GeneralStaff
{
class Troops{
private:
int nSoldiers;
public:
string name;
string rank;
void setSoldierN(int x);
Troops(string _name, string _rank)
{
name= _name;
rank= _rank;
}
};
}
void GeneralStaff::Troops::setSoldierN(int n){
nSoldiers= n;
}
Also, I have initialized name and rank according to the values passed in the constructor, because there is no need of passing them if you want to initialize the variables with a fixed value.
And the object in the main function should be created as follows:
GeneralStaff::Troops troop("John", "2");
troop.setSoldierN(10);
A external function should be defined as friend to access prive members of a class:
class Troops
{
friend void GeneralStaff::Troops setSoldierN(GeneralStaff &gs, int n);
...
};
and setSoldierN need to get an instance of Staff class to change its nSoldiers
void GeneralStaff::Troops setSoldierN(GeneralStaff &gs, int n)
{
gs.nSoldiers= n;
}

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 inherit constructor from a non-direct-parent base class

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.