I've got an assignment, some demands were made such as making an abstract baseclass for two types of questions which will be subclasses, and another demand is that all three classes have to have two constructors and that only the destructors may be empty.
So I did this in the .cpp of Question(baseclass):
Question::Question(string question)
{
this->question = question;
}
Question::Question()
{
this->question = "N/A";
}
And in one of the subclasses called "MultipleAnswerQuestion" I try doing this:
MultipleAnswerQuestion::MultipleAnswerQuestion(string question, string alternatives[],
int alternativeAmount, int correctAnswer):Question(question)
{
for(int i=0; i<alternativeAmount; i++){
this->alternatives[i] = alternatives[i]; //string
}
this->alternativeAmount = alternativeAmount; //int
this->correctAnswer = correctAnswer; //int
}
MultipleAnswerQuestion::MultipleAnswerQuestion()
{
for(int i=0; i<alternativeAmount; i++){
this->alternatives[i] = ""; //string
}
this->alternativeAmount = NULL; //int
this->correctAnswer = NULL; //int
}
And an error comes up about the bottom constructor of MultipleAnswerQuestion, saying:
"IntelliSense: class "Question" has more than one default constructor"
What's wrong?? How do I solve this?
Filling out the constructors and having two of them is a demand, so I can't just remove one.
EDIT
Class declarations:
class Question
{
public:
Question();
Question(string question = "N/A");
virtual ~Question();
void setQuestion(const string &question);
string getQuestion() const;
void print() const;
virtual void printSpec() const=0;
private:
string question;
};
And MultipleAnswerQuestion:
const int MAX = 6;
class MultipleAnswerQuestion :
public Question
{
public:
MultipleAnswerQuestion();
MultipleAnswerQuestion(string question, string alternatives[], int alternativeAmount, int correctAnswer);
virtual ~MultipleAnswerQuestion();
void printSpec() const;
void setCorrectAnswer(int correctAnswer);
void setAlternative(int alternativeNr, string alternative);
private:
int correctAnswer;
string alternatives[MAX];
int alternativeAmount;
};
You have two constructors, one default and one taking a string. However you've declared the string constructor with a default parameter, so if you try to construct one without any parameters there are two that could potentially be used. The compiler complains because it can't use both and doesn't have a rule to pick one over the other.
Either delete the default constructor, or remove the default on the string parameter.
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;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to change a subclass values Capacity, RentRate and RentMin using operation overloading. I'm newish to c++, come from java.
I want to create the objects
VanIn Van7("Large", 200, 2.0);
ManVanIn ManVan8("Abc", 99999, "Medium", 100, 1.0);
ManVan8 = Van7;
Making ManVan8 values change from "Medium, 100, 1.0" to "Large, 200, 2.0" but I keep getting a object qualifer error at the operations overload method
using namespace std;
class AbstractVan {
private:
int RentMin;
string Drivername;
long DLno;
string Capacity;
float RentRate;
public:
AbstractVan(string Drivername, long DLno, string Capacity, int RentMin, float RentRate) : Capacity(Capacity), RentMin(RentMin), RentRate(RentRate), DLno(DLno), Drivername(Drivername) {}
void setCapacity(string cap) { Capacity = cap; }
void setRentRate(float rate) {RentRate = rate;}
void setRentMin(int min) {RentMin = min;}
string getCapacity() { return Capacity; }
float getRentRate() { return RentRate; }
int getRentMin() { return RentMin; }
virtual void print() = 0;
};
Derived class from AbstractVan
class VanIn : public AbstractVan {
public:
VanIn(string Capacity, int RentMin, float RentRate) : AbstractVan(Capacity, RentMin, RentRate) {}
AbstractVan(string Drivername, long DLno, string Capacity, int RentMin, float RentRate) : Capacity(Capacity), RentMin(RentMin), RentRate(RentRate), DLno(DLno), Drivername(Drivername) {}
Derived class from VanIn
class ManVanIn : public VanIn {
private:
string Drivername;
int DLno;
public:
ManVanIn(string Drivername, long DLno, string Capacity, int RentMin, float RentRate) : VanIn(Drivername, DLno, Capacity, RentMin, RentRate){}
void print() { cout << "Drivername " << this->Drivername << " Registration " << this->DLno << " - " << getCapacity() << endl; }
~ManVanIn() {cout << "Destroy ManVanIn" << endl;}
void operator = (const VanIn &D) {
setCapacity(D.getCapacity());
setRentRate(D.getRentRate());
setRentMin(D.getRentMin());
}
};
Entry
int main()
{
VanIn Van7("Large", 200, 2.0);
ManVanIn ManVan8("Abc", 99999, "Medium", 100,1.0);
ManVan8 = Van7;
ManVan8.print();
system("pause");
return 0;
};
First of all things, as you will see later on, it's good practice to define getters with const qualifier. Otherwise it cannot be called on const object - I will get into that later.
string getCapacity() const { return Capacity; }
float getRentRate() const { return RentRate; }
int getRentMin() const { return RentMin; }
By using const qualifier you declare, that these methods only read from object and they don't change anything within the object. By following this 'rule' print() should be declared with const qualifier as well:
virtual void print() const = 0;
Second thing is if you have at least one virtual method, destructor should be virtual as well.
virtual ~AbstractVan() = default;
Next problem is in your VanIn class. Definition of constructor is wrong. VanIn is derived class from AbstractVan, therefore before creating VanIn, base class (in this case AbstractVan) must be created. Since AbstractVan doesn't have default constructor you must call parametric one (which accepts 5 arguments) in initialization section. Like this:
VanIn(string Capacity, int RentMin, float RentRate)
: AbstractVan(/* 5 parameters MUST be here */) { }
Don't forget what order of parameters is in AbstractVan constructor(e.g. it won't accept float if it expects string).
Note: you might want to use const string& in this constructor instead of string. const string& means that it is read-only reference (no unnecessary copying).
Next issue is in ManVanIn class. I don't see use of private variables. Same thing will be saved in AbstractVan after its constructor is called. Also when you call constructor of ManVanIn you try to call VanIn constructor with invalid number of arguments. Your declared version expects 3, and you give 5.
Next one is not a issue but is a good practice. When you override virtual functions use override specifier, like this:
void print() const override { /* ... */ }
It is good practice because if you try to override function which is not virtual your program won't compile (you avoid a lot of mistakes by using this). For example if you declared print function in Abstract as I did and you try override function like this:
double print() override { /* ... */ }
or even like this
void print() override { /* ... */ }
compiler will warn you that you are overriding function which is not virtual. In first case it should be clear, you didn't declare print() member function returning double. In second case it is because of missing const qualifier.
The reason why getters should be const lies here:
void operator = (const VanIn &D) {
setCapacity(D.getCapacity());
setRentRate(D.getRentRate());
setRentMin(D.getRentMin());
}
Your operator = overload accepts one parameter which is const reference to VanIn object. What you say here is that you won't change VanIn object within the body of this function. Therefore compiler cannot call non-const methods on const objects. If you miss const qualifier in these cases your program won't even compile (it should give error about discarding cv-qualifier).
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;
}
I'm new to C++, and I'm trying to write a simple code to compare two objects of subclasses of a parent class called Comparable. I want each subclass to have its own implementation of a method to compare objects based on the data they hold, so I used the virtual keyword:
class Comparable {
public:
virtual int compare(Comparable *other);
};
For example, my subclass HighScoreElement would have its own implementation of compare that would compare the score of the object to the score of another HighScoreElement.
Here is my subclass HighScoreElement:
class HighScoreElement: public Comparable {
public:
virtual int compare(Comparable *other);
HighScoreElement(string user_name, int user_score); // A constructor
private:
int score;
string name;
};
But in my compare implementation in HighScoreElement, I first try to check if the current object's data is the same as other's data. But since the pointer to other is of class Comparable and not HighScoreElement, I can't reference other->score at all in my code, even though HighScoreElement is a subclass of Comparable.
Here is the full code so far:
#include <iostream>
using namespace std;
class Comparable {
public:
virtual int compare(Comparable *other);
};
class HighScoreElement: public Comparable {
public:
virtual int compare(Comparable *other);
HighScoreElement(int user_score, string user_name);
private:
string name;
int score;
};
HighScoreElement::HighScoreElement(int user_score, string user_name) {
name = user_name;
score = user_score;
}
int HighScoreElement::compare(Comparable *other) {
if (this->score == other->score) { // Compiler error right here, other->score is invalid.
// Code to do the comparing if two scores are equal...
}
}
I get a compiler error immediately when I write this code:
if (this->score == other->score)
because other doesn't have data called score, but its subclass, HighScoreElement, does. How can I fix my function implementation so that I can reference the data of "other?" I know my question may sound vague, but any help would be appreciated!
You could implement a virtual function GetScore(), possibly pure virtual in the base class, and use that instead of accessing the field score in your compare function. Make it a const method. On the other hand, Compare could be a method implemented in the base class, that uses this->GetScore() and other->GetScore()
Code stub:
class A {
virtual int getScore() const = 0;
inline bool compare(const A* in) {return (in && this->getScore() == in->getScore());}
//return false also if "in" is set to NULL
}
class B : public A {
int score;
inline int getScore() const {return score;}
}
You can cast the pointer passed to HighScoreElement::compare using "dynamic_cast" (it throws a bad_cast exception on failure).
int HighScoreElement::compare(Comparable *other) {
HighScoreElement *h = NULL;
try
{
ptr = dynamic_cast<HighScoreElement *>(other);
}
catch(std::bad_cast const &)
{
// Handle the bad cast...
}
if (this->score == ptr->score) {
// Code to do the comparing if two scores are equal...
}
}
If you are prepared to accept null pointers, you can use dynamic casts. You can have an overload for the case when you are comparing a HighScoreElement pointer to avoid an unnecessary cast.
#include <iostream>
using namespace std;
class Comparable {
public:
virtual int compare(Comparable *other) = 0; // made pure virtual to compile without definition
};
class HighScoreElement: public Comparable {
public:
virtual int compare(Comparable *other);
int compare(HighScoreElement *other); // comparing to a HighScoreElement ptr, no need to dynamic cast
HighScoreElement(int user_score, string user_name);
private:
string name;
int score;
};
HighScoreElement::HighScoreElement(int user_score, string user_name) {
name = user_name;
score = user_score;
}
int HighScoreElement::compare(Comparable *other) {
HighScoreElement * pHSE = dynamic_cast<HighScoreElement*>(other);
if (pHSE) {
return compare(pHSE);
} else {
return -1; // or however you want to handle compare to non HighScoreElement
}
}
int HighScoreElement::compare(HighScoreElement *other) {
if (this->score == other->score) {
;
}
}
Are you sure it's not
compare( Comparable other )
If (this->score == other.score)
Let's say I have the following:
char cipan[9];
then what should I pass to the function? how about the get and set method??
I'm currently doing like this
set method
void setCipan(char cipan[]){
this->cipan = cipan;
}
and the get method
char getCipan(){
return cipan;
}
and I get an error when compiling??
Im totally blur.. can someone explain what should i pass to the function??
class userData{
private:
string name;
char dateCreate[9];
void userDataInput(string name,char dateCreate[]){
this->name = name;
this->dateCreate = dateCreate;
}
public:
//constructor
userData(string name){
userDataInput(name,dateCreate);
}
userData(string name,char dateCreate[]){
userDataInput(name,dateCreate);
}
//mutator methods
void changeName(string name){this->name = name;}
void changeDateCreate(char *dateCreate){this->dateCreate = dateCreate;}
//accesor methods
string getName(){return name;}
char *getDateCreate(){return dateCreate;}
};
I'd do the following:
void setCipan(const char* new_cipan)
{
strcpy(cipan, new_cipan);
}
const char* getCipan() const
{
return cipan;
}
Of course, the better approach is to use std::string:
void setCipan(const string& new_cipan)
{
cipan = new_cipan;
}
string getCipan() const
{
return cipan;
}
Constructor's purpose is to initialize class variables. I think it's unnecessary to call another method in the constructor to do initialization.
void userDataInput(string name,char dateCreate[]){
this->name = name;
this->dateCreate = dateCreate; // Both the dateCreate are class variables.
}
userData(string name){
userDataInput(name,dateCreate); // dateCreate is already a class variable.
}
dateCreate is the class scope variable. You are just passing it to a method, and re-assigning the same to dateCreate. Assignment operation doesn't copy elements of one array to another and are invalid operations.
To copy array elements, use std::copy instead.