Cannot call getter method unless specifying "this" keyword - c++

Why does the example from a tutorial page works without having the this keyword in the constructor?
The code from the website:
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
Rectangle ();
Rectangle (int,int);
int getWidth() {
return width;
}
};
Rectangle::Rectangle () {
width = 5;
height = 5;
}
Rectangle::Rectangle (int a, int b) {
width = a;
height = b;
}
int main () {
Rectangle rect (3,4);
Rectangle rectb;
cout << "rect area: " << rect.getWidth() << endl;
cout << "rectb area: " << rectb.getWidth() << endl;
return 0;
}
My code:
class Person {
int age;
std::string name;
public:
Person();
Person(int, std::string);
std::string * getName() {
return &name;
}
int * getAge() {
return &age;
}
};
Person::Person () {
age = 25;
name = "John";
}
Person::Person (int age, std::string name){
// This is the part :
this->age = age;
this->name = name;
}
int main() {
Person john(45, "Doe");
printf("Name %d \n", *john.getAge() );
std::cout << "Age " << *john.getName() << std::endl;
return 0;
}
As you can see in my code i must use this->name, if I don't then the values are not assigned.
On the other hand, the example code from the website works with or without this->
Why does this happen?

The problem is that the parameters of the function have the same name as the class so the compiler doesn't know which one you are talking about unless you use this. You can solve this by changing the names of the variables or you could use a member initialization list
Person::Person (int age, std::string name) : name(name), age(age) {}
As a note I like to use the same name as the class variable but add a _ after the name to make it different. So in this case I would have done:
Person::Person (int age_, std::string name_) : name(name_), age(age_) {}
This makes it easier to differentiate between the class members and the constructor parameters.

Person::Person (int age, std::string name){
// This is the part :
this->age = age;
this->name = name;
}
Because your private variable is called name, and the variable you send in is also called name, you use this-> to specify which variable called name you are using.

Related

How do you make an object as a parameter for a function c++

I am trying to make an object as a parameter for my add() function in this code:
class EnterInfo
{
protected:
string name;
int age;
string birthmonth;
public:
EnterInfo()
{
}
EnterInfo(string n, int a, string b)
{
name = n;
age = a;
birthmonth = b;
}
};
class CourseInfo
{
protected:
string title;
public:
CourseInfo()
{
}
CourseInfo(string t)
{
title = t;
}
void add()
{
}
};
int main()
{
EnterInfo s1;
CourseInfo c1;
s1 = EnterInfo("Sand", 20, "Jan");
c1 = CourseInfo(" x Records");
}
I want the add() function to gather all the data from the object "s1" and compact it into an array that I can access later. I could add, remove, or edit the data moving forward or even maybe make a new object "c2" which contains "y records" with the same s1 values ("sand", 20, "Jan"), however, I have no idea how to implement this in code.
c1.add(s1); // assume s1 (EnterInfo): Sand 20 Jan
c1.add(s2); // assume s2 (EnterInfo): Paul 23 Aug
this is the code I want to work with. I don't know how to make it work though. The end game would be this
c1.print();
output:
x records
Sand 20 Jan
Paul 23 Aug
create a vector of EnterInfo objects and put it in CourceInfo class. The code below does what you need:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class EnterInfo
{
public:
string name;
int age;
string birthmonth;
EnterInfo()
{
name = "";
age = 0;
birthmonth = "";
}
EnterInfo(string n, int a, string b)
{
name = n;
age = a;
birthmonth = b;
}
};
class CourseInfo
{
protected:
string title;
vector<EnterInfo> info_vec;
public:
CourseInfo()
{
title = "";
}
CourseInfo(string t)
{
title = t;
}
void add(const EnterInfo enterInfo)
{
this->info_vec.push_back(enterInfo);
}
void print() {
cout << this->title << endl;
for (const auto& it : this->info_vec) {
cout << it.name << " " << it.age << " " << it.birthmonth << endl;
}
}
};
int main()
{
EnterInfo s1("Sand", 20, "Jan");
EnterInfo s2("Arash", 21, "Feb");
CourseInfo c1(" x Records");
c1.add(s1);
c1.add(s2);
c1.print();
}
Side notes:
1- It's better to assign default values to the members of your class in the constructor.
2- I changed the access level of your EnterIndo members into public in order to use them in add function but the standard way is to set them to private and create getters and setters for them.
Research about std::vector and get/setters if you are not familiar with them.

EXC_BAD_ACCESS when adding object to array

I am new programming and C++. I am trying to create a Roster of Person objects using an array and then printing the attributes of the People in the Roster.
When I attempt to add a Person to the personArray, I am getting an
Exception = EXC_BAD_ACCESS (code=1, address=0x0).
I think this has to do with the scope of my personArray but I can't seem to figure it out.
Here is the code I am using:
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
class Person
{
public:
Person(string name, int age);
string getName() {
return name;
}
void setName(string n) {
name = n;
}
int getAge() {
return age;
}
void setAge(int a) {
age = a;
}
private:
string name;
int age;
};
class Roster {
public:
void addToPersonArray(string name, string age) {
Person person(name, stoi(age));
personArray[personCount] = &person;
}
void printPersonArray() {
for (int i = 0; i < 5; i++)
cout << personArray[i]->getName() << '\t' << personArray[i]->getAge() << '\n';
}
private:
Person *personArray[5];
int personCount = 0;
};
int main() {
const string studentData[] = {"Dan,45", "Mark,33", "Mary,22",
"April,17", "Jill,22"};
Roster roster;
stringstream ss(studentData[0]); // just testing the first entry
vector<string> result;
while (ss.good()) {
string substr;
getline(ss, substr, ',');
result.push_back(substr);
}
roster.printPersonArray();
}
The problem is here:
void addToPersonArray(string name, string age) {
Person person(name, stoi(age));
personArray[personCount] = &person;
}
person is a local variable in the member function addToPersonArray(), which will be destroyed after the function scope.
Hence, storing the address of a local variable(and trying to accessing it latter in printPersonArray()) will give you, nothing but an undefined behavior.
You are lucky that your programme got the exception.
One more thing to note that, you are not actually using your roster to test the program. Instead, all you do is parsing and saving to result vector. You can add this after the while loop, to make it actually work.
if (result.size() == 2) {
roster.addToPersonArray(result[0], result[1]);
}
Suggestion: Since you have a fixed array size, you probably wanna do it with std::array<Person, 5> or with std::vector<Person> by reserving the memory for 5 Person in the c'tor of Roster.
See a sample output: https://wandbox.org/permlink/tAGqqnhCfwz1wPrH
#include <iostream>
#include <sstream>
#include <vector>
#include <array>
class Person {
public:
Person(const std::string& name, int age): name(name), age(age) {}
std::string getName()const { return name; }
void setName(const std::string& n){ name = n; }
int getAge()const { return age; }
void setAge(int a) { age = a; }
private:
std::string name;
int age;
};
class Roster {
public:
Roster() { personArray.reserve(5); } // reserve some memory
void addToPersonArray(const std::string& name, const std::string& age) {
personArray.emplace_back(name, stoi(age));
}
void printPersonArray() {
// use range loop, which will assure, access what you have.
for (const Person& person: personArray)
std::cout << person.getName() << '\t' << person.getAge() << '\n';
}
private:
std::vector<Person> personArray;
//int personCount = 0; --------------> no need anymore
};
int main() {
std::array<std::string,5> studentData{ "Dan,45", "Mark,33", "Mary,22", "April,17", "Jill,22" };
Roster roster;
for(const std::string& str: studentData)
{
std::stringstream ss(str);
std::vector<std::string> result;
while (ss.good()) {
std::string substr;
std::getline(ss, substr, ',');
result.emplace_back(substr);
}
if (result.size() == 2) {
roster.addToPersonArray(result
[0], result[1]);
}
}
roster.printPersonArray();
return 0;
}
Output:
Dan 45
Mark 33
Mary 22
April 17
Jill 22
In addition to storing pointers to local variables in your addToPersonArray() function, your main() function does not add any entries to the personArray.
Instead, main creates a Roster object, and after some code that doesn't affect anything with Roster, you go straight into calling roster.printPersonArray, which does this:
void printPersonArray()
{
for (int i = 0; i < 5; i++) // <-- This will loop for all 5 entries
cout << personArray[i]->getName() << '\t' << personArray[i]->getAge() << '\n';
}
Since personArray was never initialized to contain valid pointers to Person objects, that loop will cause undefined behavior.
The issue is that you have a personCount member variable, but fail to make use of it to control how many valid entries there are in the array. The loop should have been written as below:
void printPersonArray()
{
for (int i = 0; i < personCount; i++)
cout << personArray[i]->getName() << '\t' << personArray[i]->getAge() << '\n';
}
In addition to the storage of pointers to local variables, your Roster::addToPersonArray() doesn't check if personCount is greater than 4, thus this is another place in your code where you failed to use personCount to control how many Person objects are being referenced.

The C++ method is not getting overridden?

class People {
public:
People(string name);
void setName(string name);
string getName();
void setAge(int age);
int getAge();
virtual void do_work(int x);
void setScore(double score);
double getScore();
protected:
string name;
int age;
double score;
};
class Student: public People {
public:
Student(string name);
virtual void do_work(int x);
};
class Instructor: public People {
public:
Instructor(string name);
virtual void do_work(int x);
};
People::People(string name) {
this->name = name;
this->age = rand()%100;
}
void People::setName(string name) {
this->name = name;
}
string People::getName() {
return this->name;
}
void People::setAge(int age) {
this->age = age;
}
int People::getAge() {
return this->age;
}
void People::setScore(double score) {
this->score = score;
}
double People::getScore() {
return this->score;
}
void People::do_work(int x) {
}
Student::Student(string name):People(name){
this->score = 4 * ( (double)rand() / (double)RAND_MAX );
}
void Student::do_work(int x) {
srand(x);
int hours = rand()%13;
cout << getName() << " did " << hours << " hours of homework" << endl;
}
Instructor::Instructor(string name): People(name) {
this->score = 5 * ( (double)rand() / (double)RAND_MAX );
}
void Instructor::do_work(int x) {
srand(x);
int hours = rand()%13;
cout << "Instructor " << getName() << " graded papers for " << hours << " hours " << endl;
}
int main() {
Student student1("Don");
Instructor instructor1("Mike");
People t(student1);
t.do_work(2);
}
Why the do_work class is not getting overridden ? There is a people class and the Instructor and Student class are inheriting those classes. There is a virtual method in People class, which is implemented in Student and Instructor. But it is not getting overridden ? Thanks in advance !
You need to have pointers or references to objects to make overriding work:
Student* student1 = new Student("Don");
Instructor* instructor1 = new Instructor("Mike");
People* t = student1;
t->do_work(2);
And please don't forget to delete your allocated memory:
delete student1;
delete instructor1;
That would be just enough to make it work, but for the sake of safety and avoiding memory leaks, you can just go:
#include <memory>
...
int main() {
auto student1 = std::make_unique<Student>("Don");
auto instructor1 = std::make_unique<Instructor>("Mike");
People* t = student1.get();
t->do_work(2);
}
Also please consider declaring a virtual destructor in your base class, that would be a must if you inherit from People and add a member field in the inherited class:
class People {
public:
...
virtual ~People() {}
protected:
...
}

Error: "function" is private void, error: within this context

I am fairly new to C++ and I am wanting to understand why my program is giving me this error. I constructing a program that will simulate a colony of bunnies. Being able to automatically add them, give them names, ages, etc.
These are the errors that I am getting:
main2.cpp: In function ‘int main()’:
main2.cpp:109:6: error: ‘void Bunny::printBunny()’ is private
void printBunny()
^
main2.cpp:132:26: error: within this context
colony[ i ].printBunny();
^
Here is the code that I have come up with.
enter code here
#include <iostream>
#include <string>
#include <ctime>
#include <vector>
#include <cstdlib>
using namespace std;
void setSex( void );
char getSex();
void setColor( void );
string getColor();
void setAge( void );
int getAge();
void setName( void );
string getName();
void printBunny();
static const int POSSIBLE_NAMES = 5;
static const int POSSIBLE_COLORS = 4;
class Bunny
{
char sex;
string color;
int age;
string name;
bool radioactive_mutant_vampire_bunny;
BunnyData()
{
//srand( time( 0 ) );
setSex();
setColor();
setAge();
setName();
}
void setSex()
{
int randomNumber = 1 + rand() % 2;
( randomNumber == 1 ) ? sex = 'm' : sex = 'f';
}
char getSex()
{
return sex;
}
void setColor()
{
//color = possibleColors[ 0 + rand() % POSSIBLE_COLORS ];
}
string getColor()
{
return color;
}
void setAge()
{
age = 0;
}
int getAge()
{
return age;
}
void setName()
{
//name = possibleNames[ 0 + rand() % POSSIBLE_NAMES ];
}
string getName()
{
return name;
}
void printBunny()
{
cout << "Name: " << getName() << endl;
cout << "Sex: " << getSex() << endl;
cout << "Color: " << getColor() << endl;
cout << "Age: " << getAge() << endl;
}
};
int main()
{
vector< Bunny > colony;
cout << "Welcome to Bunny Graduation!" << endl << endl;
for( int i = 0; i < 5; ++i )
{
colony.push_back( Bunny() );
}
for( int i = 0; i < 5; ++i )
{
colony[ i ].printBunny();
cout << endl;
}
return 0;
}
Everything in a class has private access unless stated otherwise For example,
class access
{
int iAmPrivate; // private. Not accessible outside of the class
public:
int getValue() //public and accessible to all
{
return iAmPrivate;
}
int iAmPublic; //also public
}
Documentation on access levels.
You need to declare them to be public, if you don't, these members are private by default, which means you cannot invoke them outside the class.
class Bunny
{public:
void printBunny() {...}
};
You really need to consider which class access modifier you should apply to the member, because normally, we don't use just one type of access modifier in OO.
You can check this site to learn more about it.
In your class:
class Bunny
{
char sex;
string color;
int age;
string name;
// Rest of class fields ...
}
All the fields are private by default. This is because you have not used the keyword public: before you declare the fields of the class Bunny. As a result, you cannot invoke/call these fields and functions outside of the class, as you have tried in:
colony[ i ].printBunny(); // you are calling a private member of class Bunny outside of the class
There are 2 ways to get around this error:
One way is that you can declare the class members as public. This will allow the functions and fields to be invoked outside of the class:
class Bunny
{
public: // declare all fields of the class as public
char sex;
string color;
int age;
string name;
// Rest of class fields ...
}
Another thing you can do is declare Bunny as a struct instead if a class. This way, all your fields sill be accessible outside the struct:
struct Bunny
{
char sex;
string color;
int age;
string name;
// Rest of class fields ...
}

C++ preprocessor and operator + overloading

I want to use the C++ preprocessor to be able to write the following in any C++ block.
class Student {
private:
int age;
int grade;
int courses;
}
int main(){
CREATE_STUDENT 15+62+2 ;
}
The previous code will create a Student with these 3 members.
I want to use + operator overloading.
Any idea of how to do it?
I want EXACTLY the syntax I mentioned above.
Why not just use a constructor:
class Student {
private:
int age;
int grade;
int courses;
public:
Student(int a, int g, int c)
{
age = a;
grade = g;
courses = c;
}
}
int main(){
Student s(15,62,2);
}
Well, I completely fail to understand why you would want to do such a thing. But it is possible, sorta.
You'll need to make it a bit more complex than that to be able to use more than one such "construct" in the same block though.
#include <iostream>
#define GRADE_STUDENT Student student = (Student)
class Student {
public:
Student(int a): age(a), grade(-1), courses(-1), setup(0) {};
Student& operator+(int p)
{
switch(setup) {
case 0: grade = p; break;
case 1: courses = p; break;
default: /* die */ char *p=0; *p=0;
}
setup++;
return *this;
};
void print()
{
std::cout << age << ", " << grade << ", " << courses << std::endl;
};
private:
int age;
int grade;
int courses;
int setup;
};
int main()
{
{
GRADE_STUDENT 15+62+2 ;
student.print();
}
{
GRADE_STUDENT 15+62 ;
student.print();
}
{
GRADE_STUDENT 15+62+2+3 ; // crash
}
return 42;
}
You should template your class instead of working with the preprocessor.