C++ : expression must be a modifiable lvalue then undefined reference to class - c++

So basically at first I wanted to change the value of CSubject "AE" with the use of a get method but, after seeing some documentation about it, doing this will cause errors like "expression must be a modifiable lvalue". So it's not possible to do such thing .
For something similar we can use a set method in this case, so that's what I did.
However, after compiling I keep geeting an error saying:
Undefined reference to CSubject::CSubject`
Why is that?
class CSubject
{
public:
CSubject() = default;
CSubject(std::string m_Name,unsigned m_SubjNr);
void setName(std::string m_Name){ Name= m_Name;}
std::string getName(){return Name;}
private:
unsigned SubjNr;
std::string Name;
};
int main()
{
CSubject a("test",3);
a.setName("Testing");
cout << a.getName();
return 0;
}

You have declared a CSubject constructor taking a std::string and an unsigned argument but have never provided an actual definition for it! Thus, the linker fails when that (used) constructor is not present in the compiled code.
To fix this, either add an 'inline' definition of that constructor, as shown here (using an initializer list for brevity):
class CSubject {
public:
CSubject() = default;
CSubject(std::string m_Name, unsigned m_SubjNr) : SubjNr{ m_SubjNr }, Name{ m_Name } {}
void setName(std::string m_Name) { Name = m_Name; }
std::string getName() { return Name; }
private:
unsigned SubjNr;
std::string Name;
};
Or, keeping your class declaration as it is, you can provide an 'out-of-body' definition of the constructor, elsewhere in the code, like this (here using 'old-style' long-hand member initialization):
CSubject::CSubject(std::string m_Name, unsigned m_SubjNr)
{
Name = m_Name;
SubjNr = m_SubjNr;
}
Use one or the other, but not both!

Related

c++ when working with class containing vectors - candidate expects 2 arguments, 0 provided

class myItem {
int key;
string name;
public:
// Constructor
myItem(int key, string name)
{
key = key;
name = name;
}
};
class myCollection {
vector<myItem> col;
public:
void insert(myItem &i);
void print();
};
int main() {
myCollection c;
int key;
string name;
cin >> key;
cin >> name;
myItem i = myItem(key, name);
c.insert(i);
c.print();
}
When I try to compile this, I get the error: no matching function for call to ‘myItem::myItem()’ and note: candidate: myItem::myItem(int, std::string). candidate expects 2 arguments, 0 provided. How might I fix this? Thanks!
First off, I am not a fan of confusing the compiler with similar names. This is terrible practice (and I am not a fan of the java this.local = param)
And even if you can argue the compiler knows what is right, someone maintaining your code will not. So you could at least capitalize or suffic and underscore or something else if you don't want to rename (sometimes I saw prefixing it with in, like inKey, inName as an alternative method which I am all in favor for, the underscore is a good if you don't want to make the name change to stand out, just make sure the underscore is not in front of the variable/parameter name):
int key;
string name;
public:
// Constructor
myItem(int key_, string name_) : key(key_), name(name_) {}
Moving on, I don't get your error but I do get unresolved externals. The problem is myCollection is defined, but not implemented (or rather its methods aren't). Try an empty placeholder using {}.
class myCollection {
vector<myItem> col;
public:
void insert(myItem &i) {}
void print() {}
};
This should fix your errors.
Your Constructor is named Team and not myItem
Replace it with
myItem(int key, string name)
{
key = key;
name = name;
}
The vector you are using in myCollection internally uses the default constructor. Try using a pointer of myItem in the vector or specify the default and copy constructors too.

C++ Setter member function with const reference causes "read access violation" exception at run-time

How do I create a class setter member function that uses const reference as its parameters? I wrote the definition of the setter of how I thought it should be, but upon running it breaks and returns a "read access violation" exception.
//==== Start of Main.cpp ====
int main()
{
std::string temp="test";
NodeData thingy;
thingy.setname(temp);
return 0;
}
//==== End of Main.cpp ====
//==== Start of NodeData.hpp====
class NodeData
{
public:
void setname(const std::string &newName);
private:
std::string *mpName;
};
//==== End of NodeData.hpp ====
//==== Start of NodeData.cpp====
void NodeData::setname(const std::string &newName)
{
*(this->mpName)=newName;//this here is what causes compiler error I think
//mpName=newName; Doesn't work because "no suitable conversion function from "const std::string" to "std::string *" exists"
}
The obvious answer is to not use a pointer in your class.
class NodeData
{
public:
void setname(const std::string &newName);
private:
std::string mpName;
};
void NodeData::setname(const std::string &newName)
{
mpName = newName;
}
Newbies often use pointers inappropriately, did you have a good reason for using a pointer in your class?

Inheritance and small number of parameters

Uncle Bob in his Clean Code suggests that no more than 3 arguments should a function get:
Functions that take three arguments are significantly harder to
understand than dyads. The issues of ordering, pausing, and ignoring
are more than doubled. I suggest you think very carefully before
creating a triad.
But what about CTOR arguments in class inheritance hierarchy? What if each class in hierarchy adds a new field and you should initialize them in CTOR. See an example below:
class Person
{
private:
std::string m_name;
int m_age;
public:
Person(const std::string& name, const int age);
std::string getName() const { return m_name; }
int getAge() const { return m_age; }
~Person();
};
class Student : public Person
{
private:
std::string m_university;
int m_grade;
public:
Student(const std::string& name, const int age, const std::string& university, const int grade);
std::string getUniversity() const { return m_university; }
int getGrade() const { return m_grade; }
~Student();
};
See how Student gets 4 arguments, while Person gets only 2 and Student adds two more. So how we should handle this?
There are several ways.
Combine multiple parameters into a struct
struct PersonInfo {
std::string name;
int age;
};
struct StudentInfo {
PersonInfo person_info;
std::string university;
int grade;
};
Person::Person(const PersonInfo &info) :m_name(info.name), m_age(info.age) {}
Student::Student(const StudentInfo &info) : Person(info.person_info), m_university(info.university), m_grade(info.grade) {}
Default initialize data members and set them with setter utilities
Person::Person() : m_age(0) {}
void Person::set_age(int age) { m_age = age; }
Student() : m_grade(0) {} // Person is default constructed.
void Student::set_grade(int grade) { m_grade = grade; }
i'd say this was just a suggestion. it's fully up to you - how many arguments should your functions get.
but if you prefer to follow the rule, make some sort of parameters holder, like:
class Student
{
public:
struct StudentParameters
{
...
};
Student(name, age, const StudentParameters &sp);
...
};
You're confusing two distinct meanings of the word function.
The first meaning is more related to the original mathematical meaning of the word. In this case, function is a named relation between one or more inputs and exactly one output. The "Clean Code" rules refers to this meaning, and tells you that more should be limited to 3 inputs.
The alternative meaning in C++ refers to a block of code, which may or may have inputs, which may or may have an output, which may or may have a name.
And yes, even in the latter sense, constructors are unusual functions. They never have a return type, not even void, and they don't have names. So you can rationalize that they're also special when it comes to their number of input arguments.

Use singleton classes in c++

I created a singleton class
class AreaDataRepository {
private:
AreaDataRepository();
AreaDataRepository(const AreaDataRepository& orig);
virtual ~AreaDataRepository();
Way onGoingWay;
public:
static AreaDataRepository& Instance()
{
static AreaDataRepository singleton;
return singleton;
}
void SetOnGoingWay(Way onGoingWay);
Way const & GetOnGoingWay() const;
};
void AreaDataRepository::SetOnGoingWay(Way onGoingWay) {
this->onGoingWay = onGoingWay;
}
Way const & AreaDataRepository::GetOnGoingWay() const {
return onGoingWay;
}
header file of Way
class Way {
private:
std::string id;
std::string name;
public:
Way();
Way(const Way& orig);
virtual ~Way();
void SetName(std::string name);
std::string const & GetName() const;
void SetId(std::string id);
std::string const & GetId() const;
};
Then i'm created a Way object and set vales of id and name.
Way wayNode;
wayNode.SetId("123");
wayNode.SetName("jan")
AreaDataRepository::Instance().SetOnGoingWay(wayNode);
After assign OngoingWay accessing it from another class.
std::cout << AreaDataRepository::Instance().GetOnGoingWay().GetId();
the vale is not printing.
I'm going psychic here.... and I divine that your implementation of SetId is like this:
void SetId(std::string id) { id = id; }
that does not set the member variable, that sets the parameter to itself. And since your constructor most likely set the member variable id to "" you're printing empty strings. Either change the name of the parameter (to newId for example) to avoid the conflict or change the implementation to:
void SetId(std::string id) { this->id = id; }
As proof of this claim here's the result for the first version, as you see it prints nothing. And here is the result for the second, as you can see it prints the number.
The problem boils down to this: you have function parameter names that are the same as the name of your member variables and the function parameters are shadowing/hiding the member variables.
The only place this cannot happen is in a constructor's initialization list:
class Foo {
int x;
public:
Foo(int x): x(x) {} // <-- this works
void SetX(int x) { x = x; } // <-- this won't the parameter is hiding the member variable
};
Demo for the above snippet
std::cout is buffered in most implementations, if not in all. That means, the stream will wait for you to end a line before writing out any data. So, you can easily fix this by changing your output statement to
std::cout << AreaDataRepository::Instance().GetOnGoingWay().GetId() << std::endl;

passing an array of character to function c++

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.