C++ class does not output correct data? - c++

No compilation error but the output is this:
g++ class.cpp && ./a.out
is -1003073000 years old.
It does not output the string and int as it supposed to be.
I don't know what is wrong, I would really appreciate if someone point out my mistake, thanks!.
Here is the code:
#include<iostream>
class Student{
private:
std::string name;
int age;
public:
Student(std::string name, int age){
name = name;
age = age;
}
void setName(std::string name){
name = name;
}
std::string getName(){
return name;
}
void setAge(int age){
age = age;
}
int getAge(){
return age;
}
};
int main(){
Student student1 = Student("Clayton",20);
std::cout<<student1.getName();<<" is "<< student1.getAge()<<" years old."<<std::endl;
}

In the constructor
Student(std::string name, int age){
name = name;
age = age;
}
The names name and age are the argument variables of those names. Which means you assign the variables to themselves.
That will leave the Student::name member default constructed and empty, but the Student::age variable will be uninitialized, and have an indeterminate value, and using such values (even printing them) is undefined behavior.
You have two solutions:
Use this to explicitly reference the current object and use its member variables:
Student(std::string name, int age){
this->name = name;
this->age = age;
}
Or use a member initializer list to initialize (rather than assign to) the member variables:
Student(std::string name, int age) : name(name), age(age) {
// Empty
}
For this the language knows the difference between the member and argument variables.
I highly recommend the second alternative.

Related

C26495 Variable 'Employee::age' is uninitialized. Always initialize a member variable (type.6)

this is my code:-
#include<iostream>
using std::string;
//bydefault private cant access attributes outside class
class Employee{
public:
string name;
string company;
int age=0;
void Introduce() {
std::cout << "my age is- " << age << std::endl;
}
Employee(string company, string name, int age) {
name = name;
company = company;
age = age;
}
};
int main() {
Employee emp1 = Employee("bww","susmit",24);
emp1.Introduce();
//Employee emp2;
//same example
}
Output is my age is 0
I want it to be what I entered emp1 args to be
please help.
This constructor
Employee(string company, string name, int age) {
name = name;
company = company;
age = age;
}
is incorrect. Within the body of the constructor you are assigning parameters to themselves. It is because the parameters hide data members with the same name within the body of the constructor.
At least you should write
Employee(string company, string name, int age) {
this->name = name;
this->company = company;
this->age = age;
}
But it would be even better to use a mem-initializer list like
Employee(const std::string &company, const std::string &name, int age)
: name( name ), company( company ), age( age )
{
}
And in main you may write
Employee emp1("bww","susmit",24);
instead of
Employee emp1 = Employee("bww","susmit",24);
As for the function Introduce then it is better to declare and define it the following way
std::ostream & Introduce( std::ostream &os = std::cout ) const
{
os << "my age is- " << age << std::endl;
return os;
}
Also there is no great sense to declare these data members
string name;
string company;
int age=0;
as having a public access. You could declare them as having private access.
Also as your class does not have the default constructor then this member initialization within the class definition
int age=0;
is redundant.
Your constructor just assigns the arguments given to the constructor to themselves:
Employee(string company, string name, int age) {
// ^
// |
name = name; // -------------+ both left and right name refer to the argument
company = company;
age = age;
}
You could solve it by using a different name for the constructor arguments (or by being explicit using this->member = ...) or by using the member initializer-list:
Employee(string company, string name, int age) : // colon starts the member init-list
name(name), // The first name refers to the member varible (this->name)
company(company), // and the second refers to the constructor argument
age(age) //
{
// constructor body can now be empty
}

C++ Null output when a function is called

Below is a snippet of code from my main program
My H file
class Person{
public:
std::string name;
int rangeStance;
int initialStance;
Person(std::string name, int rangeStance, int initialStance){
name = name;
rangeStance = rangeStance;
initialStance = initialStance;
setName(getName());
setRangestance(getRangeStance());
setinitalStance(getRangeStance());
}
Person();
void setName(std::string name);
void setRangestance(int range);
void setinitalStance(int stance);
std::string getName();
int getRangeStance();
int getinitalStance();
double impact(int rangeStance, int initalStance);
};
class Leader: public Person {
public:
int popularity;
int totalcountryVotes;
Leader(std::string name, int rangeStance, int initialStance,int popularity, int totalcountryVotes)
:Person(name, rangeStance, initialStance), popularity(popularity), totalcountryVotes(totalcountryVotes){
popularity = popularity;
totalcountryVotes = totalcountryVotes;
setPopularity(getPopularity());
setTotalcountryVotes(getTotalcountryVotes());
}
Leader();
void setPopularity(int popularity);
void setTotalcountryVotes(int totalcountryVotes);
int getPopularity();
int getTotalcountryVotes();
};
The corresponding functions in the main cpp file.
Person::Person() {
}
void Person::setName(string Name)
{
name = Name;
}
string Person::getName() {
return name;
}
void Person::setRangestance(int Range)
{
rangeStance = Range;
}
int Person::getRangeStance() {
return rangeStance;
}
void Person::setinitalStance(int stance)
{
initialStance = stance;
}
int Person::getinitalStance() {
return initialStance;
}
Leader::Leader() {
}
void Leader::setPopularity(int popularity) {
popularity = popularity;
}
void Leader::setTotalcountryVotes(int totalcountryVotes) {
totalcountryVotes = totalcountryVotes;
}
int Leader::getPopularity() {
return popularity;
}
int Leader::getTotalcountryVotes() {
return totalcountryVotes;
}
Within main the needed funtions are called appropriately
int main(int argc, char* argv[]) {
Leader labourLeader("George Lopez",100,50,50, 75);//sets record for the labour party leader
cout << "--Party Leader--" << endl;
cout << labourLeader.getName() << endl;
return 0;
}
However when this snippet of code is compiled, no outcome is returned where it should be printing out "George Lopez". Im fairly "noob" with c++, am i using my contructor right or should I be delcaring it within my h file? Thankyou.
A couple of things wrong in this code
Person(std::string name, int rangeStance, int initialStance){
name = name;
rangeStance = rangeStance;
initialStance = initialStance;
setName(getName());
setRangestance(getRangeStance());
setinitalStance(getRangeStance());
}
Firstly it's not necessary to call setters and to do assignments, so lets drop those, leaving
Person(std::string name, int rangeStance, int initialStance){
name = name;
rangeStance = rangeStance;
initialStance = initialStance;
}
Now think about what name = name does. Does that look curious to you at all? It takes the parameter name and assigns it to the parameter name! The member variable also called name is completely unchanged. This situation where one name hides another similar name is called shadowing.
Person(std::string name, int rangeStance, int initialStance) {
name = name;
What's happening there is that it's just overwriting the parameter with itself, rather than copying it to the member variable. That's because the name lookup rules for unqualified names at that point prefer the parameter to the member variable. That means the member variable is being left at its constructed state, an empty string.
There are a few ways to fix this. The first is to simply name them differently so that there's no ambiguity, such as the common method of prefixing member variables with m_. That way, the statement becomes the more explicit:
m_name = name;
Another alternative is to be explicit about the one you're assigning to so that it's no longer unqualified:
this->name = name;
A third is to use initialiser lists where the rules are slightly different in that it uses the member variable outside the parentheses and does normal unqualified lookup within the parentheses:
Person(std::string name, int rangeStance, int initialStance)
: name(name)
, rangeStance(rangeStance)
, initialStance(initialStance)
// ^ ^
// | |
// | +- normal lookup, passed-in parameter.
// +--------------- member variable.
{
};
And there's no need to have all those other statements in the constructor, such as setName(getName()), since you've already set the name.

Class constructor not saving variables

When trying to use a getter to obtain the value of the variable in my Employee class, nothing is returned or output.
I have tried using setters, which wouldn't do much as they still use the this-> method, but nothing reaches what I have set.
class Employee {
Employee(int empNum, std::string name, std::string address, std::string
phone);
private:
int empNum;
std::string name;
std::string address;
std::string phone;
};
class HourlyEmployee : public Employee {
HourlyEmployee(int empNum, std::string name, std::string address,
std::string phone, double hourlyWage, double hoursWorked);
//getters
double getHoursWorked();
double getHourlyWage();
//setters
void setHoursWorked(double hoursWorked);
void setHourlyWage(double hourlyWage);
private:
double hoursWorked;
double hourlyWage;
}
//CPP file
Employee::Employee(int empNum, std::string name, std::string address,
std::string phone) {
this->empNum = empNum;
this->name = name;
this->address = address;
this->phone = phone;
}
HourlyEmployee::HourlyEmployee(int empNum, std::string name, std::string
address, std::string phone, double hoursWorked, double hourlyWage) {
Employee(empNum, name, address, phone);
this->hoursWorked = hoursWorked;
this->hourlyWage = hourlyWage;
}
//main
HourlyEmployee hourly1(1, "H. Potter", "Privet Drive", "201-9090", 12.00,
40.00);
cout << hourly1.getPhone() << " " << hourly1.getName() << " " <<
hourly1.getHoursWorked();
This is not the full code, but it should output the phone and name and the hours worked, but for some reason it is only outputting two spaces and then the hoursWorked. I can only assume that the name, phone, etc. variables have not actually been set, therefore they are not returning anything. So how do I get it to set those variables?
C++ doesn't treat constructor invocations specially in constructor bodies. The following line
Employee(empNum, name, address, phone);
will construct a new, completely separate instance of Employee, and then discard it, because the resulting object isn't assigned to anything. The values of that object's fields aren't copied to the instance of HourlyEmployee you're creating.
To make use of the superclass constructor in the subclass one, use a member initializer list in the definition of the subclass constructor.
HourlyEmployee::HourlyEmployee(int empNum, std::string name, std::string
address, std::string phone, double hoursWorked, double hourlyWage)
: Employee(empNum, name, address, phone) {
this->hoursWorked = hoursWorked;
this->hourlyWage = hourlyWage;
}
This way, C++ will invoke the constructor of Employee to initialize the same object that this constructor of HourlyEmployee is initializing.
You can even go a bit further and reduce your constructors to just member initializer lists. A nice side effect is that this avoids having to type this-> or come up with different naming schemes.
Employee::Employee(int empNum, std::string name, std::string address,
std::string phone)
: empNum(empNum),
name(name),
address(address),
phone(phone) {}
HourlyEmployee::HourlyEmployee(int empNum, std::string name, std::string
address, std::string phone, double hoursWorked, double hourlyWage)
: Employee(empNum, name, address, phone),
hoursWorked(hoursWorked),
hourlyWage(hourlyWage) {}
You can learn more from the link above, but to quote a short bit of explanation:
Before the compound statement that forms the function body of the constructor begins executing, initialization of all direct bases, virtual bases, and non-static data members is finished. Member initializer list is the place where non-default initialization of these objects can be specified.
The constructor of the derived class HourlyEmployee calls the base contructor in a wrong way.
You should write the code like this:
HourlyEmployee::HourlyEmployee(int empNum, std::string name, std::string
address, std::string phone, double hoursWorked, double hourlyWage) :
Employee(empNum, name, address, phone)
{
this->hoursWorked = hoursWorked;
this->hourlyWage = hourlyWage;
}
Also, the parameter name of all your constructors are same as your member names, this is NOT a good idea. Better name them differently.
You need to use an initializer list in the constructor of the subclass, like this:
#include <iostream>
class Employee {
public:
Employee(int empNum, std::string name, std::string address, std::string phone) {
this->empNum = empNum;
this->name = name;
this->address = address;
this->phone = phone;
}
std::string getPhone() { return phone; }
std::string getName() { return name; }
private:
int empNum;
std::string name;
std::string address;
std::string phone;
};
class HourlyEmployee : public Employee {
public:
HourlyEmployee(int empNum, std::string name, std::string address, std::string phone, double hoursWorked, double hourlyWage)
: Employee(empNum, name, address, phone) {
this->hoursWorked = hoursWorked;
this->hourlyWage = hourlyWage;
}
double getHoursWorked() { return hoursWorked; }
double getHourlyWage() { return hourlyWage; }
private:
double hoursWorked;
double hourlyWage;
};
int main(void)
{
HourlyEmployee hourly1(1, "H. Potter", "Privet Drive", "201-9090", 12.00, 40.00);
std::cout << hourly1.getPhone() << " " << hourly1.getName() << " " <<
hourly1.getHoursWorked();
return 0;
}
Output:
201-9090 H. Potter 12
However, I strongly advise you use the initialization list for all your class's data members, namely both for the base and derived class in this case.

C++: how to make getters and setters work with an empty constructor

First of all, I have only learned a little bit of Java before. It's been only a few days since I started getting friendly with C++ so please don't take this question so basic and please don't degrade my question.
I made a simple source code as follows:
#include <iostream>
using namespace std;
class Car {
public:
void setBrand(string name);
void setPrice(double price);
string getBrand();
double getPrice();
Car();
Car(string name);
Car(string name, double price);
private:
string name;
double price;
};
Car::Car() {
}
Car::Car(string name) {
name = name;
}
Car::Car(string name, double price) {
name = name;
price = price;
}
void Car::setBrand(string name) {
name = name;
}
void Car::setPrice(double price) {
price = price;
}
string Car::getBrand(void) {
return name;
}
double Car::getPrice(void) {
return price;
}
int main() {
Car car;
car.setBrand("Nissan");
car.setPrice(30000);
cout << "Brand: " << car.getBrand() << endl;
cout << "Price: " << car.getPrice() << endl;
return 0;
}
I wanted to make a code that creates an empty instance of a class called Car, set the field values later and print them out on the console.
The code did not make any errors during the compile, but the result I see was totally different from what I expected. It didn't show the brand name and the price was looking even weird, as follows.
Brand:
Price: 6.95322e-310
Somebody help me out! Thank you very much indeed in advance.
The problem you have is that you override the member names with function parameters. You can use this-> to make it explicit or name the member differently.
For example:
void Car::setBrand(string name) {
this->name = name;
}
Or:
void Car::setBrand(string new_name) {
name = new_name;
}
In your constructor and setters, you make no differentiation between the local parameter and the class member.
name = name;
Both the function parameter and the class member are called name. Currently the compiler is assigning the parameter value to itself, and not affecting the class member at all. This is because the function parameter is in a more immediate scope.
Possible solutions:
Specify this when referring to the class member: this->name = name;.
Rename the function parameter: name = _name;.
For the constructor, use initializer lists:
Car::Car(string name, double price)
: name(name)
, price(price)
{ }
There's too much wrong with your code to describe it in prose, so let me present a fixed implementation, and I leave it to you to spot the difference:
#include <string>
class Car
{
private:
static constexpr double kNoPrice = -1.0;
static constexpr const char* kNoName = "[no name]";
public:
// Main constructor: constructs a car with the given name and price.
Car(std::string name, double price)
: name_(std::move(name))
, price_(price)
{}
// Convenience constructors:
Car() : Car(kNoName, kNoPrice) {}
Car(std::string name) : Car(std::move(name), kNoPrice) {}
// Accessors:
const std::string& getBrand() const { return name_; }
void setBrand(std::string name) { name_ = std::move(name); }
double getPrice() const { return price_; }
void setPrice(double price) { price_ = price; }
private:
std::string name;
double price;
};
Some random notes, in no particular order:
Use correct names. It's std::string, not string, mate or buddy. Never ever be abusing namespace std.
Include headers for external names that you need.
Reading uninitialized values is undefined behaviour, so none of your constructors should leave fields uninitialized (like price_).
Give private members consistent names (e.g. foo_ in my example).
Accessors should be const-correct.
Convenience constructors should delegate to one single work-horse constructor.
Pick sensible defaults for initial values of defaulted fields and make them discoverable.
Use move semantics when taking ownership of dynamically managed data (strings, dynamic containers, etc.).

Is there an automatic way to initialize private variables - instead of accepting them as constructor arguments?

I am trying to use the constructor to initialize a private variable but when looking at the code this seems annoying and repeatitive.
class Parent
{
public:
Parent(string _name, string _eyecolor, string _skincolor, string _gender, int _age)
{
// Cluttered
_name = name;
_eyecolor = eyecolor;
_skincolor = skincolor;
_gender = gender;
_age = age;
}
private:
string name, eyecolor, skincolor, gender;
int age;
};
You can define a default constructor that makes use of another constructor you defined in C++11:
class Parent
{
public:
Parent() :
Parent("Richard", "Pink", "Green", "Male", 777)
{}
Parent(string _name, string _eyecolor, string _skincolor, string _gender, int _age)
{
// Cluttered
_name = name;
_eyecolor = eyecolor;
_skincolor = skincolor;
_gender = gender;
_age = age;
}
private:
string name, eyecolor, skincolor, gender;
int age;
};
If your compiler doesn't support this feature you can always do it manually:
class Parent
{
public:
Parent() :
name("Richard"),
eyecolor("Pink"),
skincolor("Green"),
gender("Male"),
age(777)
{}
Parent(string _name, string _eyecolor, string _skincolor, string _gender, int _age)
{
// Cluttered
_name = name;
_eyecolor = eyecolor;
_skincolor = skincolor;
_gender = gender;
_age = age;
}
private:
string name, eyecolor, skincolor, gender;
int age;
};
No there's not a way to automatically initialize member variables. If you think about it, that would be terrible if there was. How would the compiler know what you wanted to initialize the variables with?
As others said, you're not actually initializing the members. You aren't even assigning anything to them. You're assigning the member variables to the constructor's arguments here. Look up the syntax for initializing member variables in a constructor. It could be something like this, buy maybe formatted however you like it (I'm on a tablet so I can't format it too well).
class Parent {
public:
Parent(string _name, string _eyecolor, string _skincolor, string _gender, int _age)
: name{ _name }, eyecolor{ _eyecolor }, skincolor{ _skincolor }, gender{ _gender }, age{ _age }
{
}
private:
string name, eyecolor, skincolor, gender;
int age;
};
If you mean you want to initialize them with some (defined) value without passing arguments, you can initialize them with a default constructor, essentially the same way I did above.