I'm writing the following program.
Write a class called CAccount which contains two
private data elements, an integer accountNumber
and a floating point accountBalance, and three
member functions:
A constructor that allows the user to set
initial values for accountNumber and
accountBalance and a default constructor
that prompts for the input of the values for
the above data members.
A function called inputTransaction,
which reads a character value for
transactionType ('D' for deposit
and 'W' for withdrawal), and a floating point
value for transactionAmount, which
updates accountBalance.
A function called printBalance, which
prints on the screen the accountNumber
and accountBalance.
--
#include <iostream>
using namespace std;
class CAccount{
public:
CAccount(){
setValues(2, 5);
printBalance();
inputTransaction();
printBalance();
}
void setValues(int aN, int aB);
void inputTransaction();
void printBalance();
private:
int accountNumber;
float accountBalance;
};
void CAccount::setValues(int aN, int aB){
accountNumber = aN;
accountBalance = aB;
}
void CAccount::inputTransaction(){
char transactionType;
float transactionAmount;
cout << "Type of transaction? D - Deposit, W - Withdrawal" << endl;
cin >> transactionType;
cout << "Input the amount you want to deposit/withdraw" << endl;
cin >> transactionAmount;
if(transactionType == 'D'){
accountBalance += transactionAmount;
}
else if(transactionType == 'W'){
accountBalance -= transactionAmount;
}
}
void CAccount::printBalance(){
cout << "Account number : " << accountNumber << endl << "Account balance : " << accountBalance << endl;
}
int main ()
{
CAccount client;
}
I don't understand this part :
1. A constructor that allows the user to set
initial values for accountNumber and
accountBalance and a default constructor
that prompts for the input of the values for
the above data members.
What exactly is the difference between a constructor and default constructor, I'm kinda confused on this step.
Other than that, I would like to ask people with more experience to tell me any tips I should follow when coding with classes and which mistakes to avoid (this is my first class I ever wrote in C++).
A Default constructor is defined to have no arguments at all as opposed to a constructor in general which can have as many arguments as you wish.
Your second question is far too general to be answered here. Please turn to the many many sources in the net. stackoverflow is for specific questions not for tutorials.
If you don't define a constructor for a class, a default parameterless constructor is automatically created by the compiler. Default constructor is created only if there are no constructors. If you define any constructor for your class, no default constructor is automatically created.
A default constructor is one that doesn't need to be given arguments, either because it doesn't have any, or the ones it has have default values. Such constructors are special in the sense that say Type var; or Type var[10];
or new Type(); invoke and require them.
See how you've written void CAccount::setValues(int aN, int aB)? If you change setValues to CAccount it becomes another constructor with 2 int arguments... that's a user-defined non-default constructor and satisfies your requirements.
As is, because you only have one constructor that doesn't take any arguments but reads inputs from stdin, you're forcing users to use that constructor, read inputs, and if you call setValues you'd be overwriting those values with the setValue arguments....
Default constructor is one type of constructor.
Where as we have other conctructors namely:
Parameterised constructor
Copy constructor
If we don't define any constructor then a default constructor is provided. But if we define any constructor then no default constructor is provided.
Default constructor doesn't take any parameter. Where as other constructors need parameter.
For your 2nd question:
If you define any constructor (parameterised or copy constructor) then you should define a default constructor also. Otherwise code like
ClassName obj = new ClassName();
will give build error. But this again depends upon your requirement and usecase.
And constructor is generally used for initialization. But you have called some functions inside constructor which is generally not done.
The default constructor is a compiler generated parameter-less constructor. You can explicitly define a constructor taking zero arguments but not everybody would call it a default constructor.
Your program should define a constructor with parameters for accountNumber and accountBalance, and a parameter-less one that prompts the user. Like this:
#include <iostream>
using namespace std;
class CAccount {
public:
/**
* Constructor prompting the user for accountNumber and accountBalance
*/
CAccount()
{
inputTransaction();
printBalance();
}
/**
* Constructor initializing accountNumber and accountBalance with parameters
*/
CAccount(int accountNumber, float accountBalance)
: accountNumber(accountNumber),
accountBalance(accountBalance)
{
printBalance();
}
void inputTransaction() { /* Implement me. */ }
void printBalance() { /* Implement me. */ }
private:
int accountNumber;
float accountBalance;
};
As you can see, I used initializers for accountNumber and accountBalance in the constructor taking those arguments. That is what you should always do.
Related
This is my first question on here, so excuse me if I've formatted everything in a wrong way.
So, to get to the problem - this is s university assignment of mine. The goal is to create a class called Student, which has a few fields, and store the instances in an array of Student objects. One of the tasks is to have a static variable inside the class that keeps track of how many Student instances have been created. To clarify, I have a getData() method that asks the user for the values, and then sets the current object's values to those entered (basically just like a constructor, which makes the constructors obsolete, but they want us to do it that way for some reason). In the getData() function, the static count variable gets raised by 1, as well as in the constructors, and gets decremented in the destructor.
The issue is that for some reason, Student::amount variable sets itself to 100. Every time that i try to access it from the main() function, its 100 plus the amount of students created, so if we have created 2 students, Student::amount will be equal to 102. I've nowhere explicitly set it to that number, which also matches the size of the array, by the way.
I'm still rather new to C++, I've read and watched some material on how OOP works here, but I've barely even scratched the surface.
Sorry again if my question is badly formulated or/and badly formatted, and I hope you can help me with this!
#include <iostream>
#include <string>
using namespace std;
class Date {
...
};
class Student {
// Fields
private:
string name = "";
string PID = "";
int marks[5]{ 0 };
short course = 0;
public:
// Count of all students
static int amount;
// Getters
...
// Setters
...
// Constructors
Student(); // Default one, Student::amount gets raised by 1 there
Student(string name, string PID, int marks[5], short course);
// Destructor
~Student();
// Methods
void getData();
void display(); // Display the information of a student
};
// Array of students
Student students[100];
// Student::Count
int Student::amount; // Initializes with 0 if not explicitly initialized
void Student::getData() {
cin.ignore();
cout << "\nName: "; getline(cin, name);
cout << "PID: "; getline(cin, PID);
cout << "Marks:\n";
for (int i = 0; i < 5; i++)
{
cin >> marks[i];
}
cout << "Course: "; cin >> course;
Student::amount++;
}
Student::Student(string name, string PID, int marks[5], short course) {
this->setName(name);
this->setPID(PID);
this->setMarks(marks);
this->setCourse(course);
Student::amount++;
}
The global declaration Student students[100]; calls the default Student constructor 100 times, before main is reached. According to your comment (you don't supply the constructor implementation), that constructor increases amount by 1.
A solution here is to remove Student::amount and instead use
std::vector<Student> students;
students.size() will give you the number of students in that container. Use push_back to put students into the vector.
A very crude alternative that at least is broadly compliant with the question constraints is to remove the amount increment from the default constructor, and all other places apart from the four argument constructor.
I'm an aspiring software engineer and full-time CS student. During the holiday break, I have been working on exercises to be better at my craft (C++). There are topics that I just need some clarity on. I'm working on a Target Heart Rate Calculator.
I have spent hours, days, trying to understand the concept of the constructor vs default constructor. I know that a constructor is required for every object created.
Before going any further, I want to test my code where it prompts the user to enter their first name and then return it. For once and for all, for the slow learners out there struggling including myself, can anyone please just explain this in Layman's terms with a visual explanation, please?
Below is my code. I'm receiving an error:
no matching function for call to 'HeartRates::HeartRates()'
main.cpp
int main() {
HeartRates patient;
cout << "First name: ";
string firstName;
cin >> firstName;
patient.setFirstName(firstName);
patient.getFirstName();
return 0;
HeartRate.h
// create a class called HeartRates
class HeartRates {
public:
// constructor receiving data
HeartRates(string personFirstName, string personLastName, int month, int day, int year) {
firstName = personFirstName;
lastName = personLastName;
birthMonth = month;
birthDay = day;
birthYear = year;
}
void setFirstName(string personFirstName) {
firstName = personFirstName;
}
string getFirstName() {
return firstName;
}
private:
// attributes
string firstName, lastName;
int birthMonth, birthDay, birthYear;
};
Thank you, everyone! Sheesh! My book adds all these extra words that aren't necessary and makes the reading hard. All it had to say was:
If you want to create an object to receive information from a user, make sure your constructor has empty (). If you have data to input manually, pass that data through your constructor's parameters.
I hope this was the guise of your explanation. I love this community - thank you so much! You all have no idea about my back story - basically transitioning from a 15 years marketing/advertising career to becoming a software engineer. You all have been so welcoming and it confirms I made a great decision to switch.🙌🏽✊🏽🤝🏽🙏🏽
Here is my updated code:
main.cpp
int main() {
HeartRates patient;
cout << "First name: ";
string firstName;
cin >> firstName;
patient.setFirstName(firstName);
cout << patient.getFirstName();
return 0;
}
HeartRates.h
// create a class called HeartRates
class HeartRates {
public:
// constructor receiving data - THANKS STACKOVERFLOW COMMUNITY
HeartRates() {
firstName;
lastName;
birthMonth;
birthDay;
birthYear;
}
void setFirstName(string personFirstName) {
firstName = personFirstName;
}
string getFirstName() {
return firstName;
}
private:
// attributes
string firstName, lastName;
int birthMonth, birthDay, birthYear;
};
If you don't define any constructor, you get a constructor that takes no arguments.
As soon as you defined a constructor that has arguments, your no-args constructor retired to the North Pole.
So now you must write HeartRate("first", "last", 1, 1, 2001)
If you don't want to write that, delete the parameter list from your constructor and just set whatever you want for initial values.
Default constructor is any constructor that can be called with no arguments.
MyClass() - default
MyClass(int x) - not default
MyClass(int x = 42) - default
If you don't define any constructor for your class, a compiler generates a default constructor automatically. It looks more or less like MyClass() {}.
HeartRates patient; tries to call a default constructor, since you didn't provide any arguments (that would be HeartRates patient(...);).
The difference between a default constructor and "normal" constructor is simpler than it may seem.
As long as you don't specify the constructor in your class, when creating an object of an class, it always will call the default constructor, which, if you haven't implemented one, will do nothing but creating an object of that specific class with nothing initialized. If you now have implemented your own constructor, with some parameters, the only way to construct an object of that class will require you to call the implemented constructor. Your default constructor is then overwritten.
You can imagine it as a function you only defined. Something like this:
(the function foo is in this example as your constructor)
There is always a
void foo();
function
Whenever you call foo() it will call that specific function doing nothing. And the function foo() is alway given. If you now declare a second foo function like this:
void foo(std::string name)
{
std::cout << "This is the name " << name << std::endl;
}
and you call your foo function, it will then call the new foo function that you have implemented.
Long story short, if you only have created a class with no customized constructor, you always have a default constructor that is been called when creating an object, but not really initializing something. Whenever you write your own customized constructor, it will overwrite the default constructor.
My C++ Programm always calls too more constructors than i intended to. It should create an edge, which then automatically creates two nodes by the string-input of the overloaded edge-constructor.
But it first calls the default-constructor of the node objects and then the overloaded self-defined constructor. The destructors do not delete the default nodes immediately. That causes an error in my program.
The problem is that the program should count the amount of objects and allocate an appropriate ID related to the amount of objects.
Compiler-Output
Default-Constructor
Default-Constructor
Overload-Constructor
ID: 1 numInstances: 2
Destructor
Overload-Constructor
ID: 2 numInstances: 1
Destructor
Edge: -> Node_0002
Destructor
Destructor
Program ended with exit code: 0
Here is a snippet for you to see the code which most likely causes the error:
main.cpp
int main() {
Edge e1 = Edge("1", "2");
std::cout << "Edge: " << e1.toString() << endl;
return 0;
}
node.hpp
double Node::numInstances = 0;
Node::Node()
{
numInstances++;
cout << "Default-Constructor" << endl;
double idNumber = numInstances;
m_id = setUpIdString(idNumber);
}
Node::Node(string id)
{
double idNumber = getNumberFromString(id);
cout << "Overload-Constructor" << endl;
cout << "ID: " << idNumber << " numInstances: " << numInstances << endl;
if (idNumber > numInstances) {
numInstances++;
m_id = setUpIdString(idNumber);
}
}
Node::~Node()
{
numInstances--;
cout << "Destructor" << endl;
}
edge.cpp
Edge::Edge(string src, string dst)
{
m_srcNode = Node(src);
m_dstNode = Node(dst);
}
EDIT:
node.hpp
class Node
{
public:
Node();
Node(string id);
~Node();
string getId();
private:
string m_id;
static double numInstances;
};
edge.hpp
class Edge
{
public:
Edge(Node& rSrc, Node& rDst);
Edge(string src, string dst);
string toString();
Node& getSrcNode();
Node& getDstNode();
private:
Node m_srcNode;
Node m_dstNode;
};
A constructor is not like other functions in C++. A constructor's job is to initialize an object. In order to ensure the object gets initialized in a sensible way, all of the member objects (and base objects) need to be initialized. *This happens before the opening brace of the constructor body, so that everything is in a sensible state when you're in the constructor body.
To make sure this happens in the way you want, you can use an initializer list (note that this term also refers to something else when initializing various containers; if you've heard the term before in relation to that, it's not what I'm discussing here). After the function signature, you put a colon, followed by each member of your class (in the same order they're declared in the class) and how you want to initialize it. For example, if you have the following struct
struct A {
int i;
char c;
std::string s;
A();
};
you can declare define your constructor as
A::A() : i{17}, c{'q'}, s{"Hello, mrb! Welcome to Stack Overflow"}
{
// Nothing to do in the body of the constructor
}
That way, an A object's members are initialized to 17, 'q', and a greeting before the start of the function, and are not initialized any other way.
Since you do not do this, the compiler instead uses the default constructor for the nodes. You then create other nodes inside the constructor body, and assign them to the nodes in your class.
m_srcNode = Node(src);
m_dstNode = Node(dst);
Here, the two objects are first constructed with default constructor, then the overloaded constructed is called with Node(src) and Node(dst). After that, the implicitly defined copy assigner is called to assign the temporary objects to m_srcNode and m_dstNode. Finally the temporary objects are destroyed.
If you want to avoid extra constructor calls, you can write a member initializer list:
Edge::Edge(string src, string dst) : m_srcNode(src), m_dstNode(dst) {}
Lets take the example some of the codes like the following use objects but can access their members directly without using any '.' operator
Eg-1
#include <iostream>
#include <string>
using namespace std;
int main () {
string mystr;
cout << "What's your name? ";
getline (cin, mystr);
cout << "Hello " << mystr << ".\n";
cout << "What is your favorite team? ";
getline (cin, mystr);
cout << "I like " << mystr << " too!\n";
return 0;
}
Here mystr is an object of std::string but it can access the group of characters inside it without using the '.' operator it should be
getline(cin,mystr.(member_name)); //Here member name is the name of the member which is there inside the class std::string and stores the data
But the actual working code is
getline(cin,mystr);
Second thing what is indirection
Edit 1:
Ok let me put this in a more simpler way if i have some class which has some data members and if i want to use any data member then i need to refer it from the object like
Eg-2
class reff{
public:
int a;
int b;
}
reff per;
per.a=36;
This statement tells that to access any class' members we need to refer it from the object but the same is not happening in the example of std:: string which i have mentioned above mystr is an object so it must be having some data member to store the data if i want to display the data inside a std::string object then i should mention the data member's name along with the objects name but in Eg-1 only object's name is mentioned.
The reason the call to getline(cin,mystr); does not directly specify any of the members of mystr is because the getline() function requires a string object, not one of its member variables. The actual implementation will access the individual members, but as a user of the string class, you don't need to (or want to) know those details. This concept is known as encapsulation, and allows you to seperate what a thing does (stores and allows access to a string of characters) from how it does it (pointers and length counters, static buffers, or whatever).
In your example:
class reff{
public:
int a;
int b;
};
reff per;
per.a=36;
you directly access the a member, but we could write a function which requires a reference to a reff object to set the value of its member variable:
void setValueA(reff& obj, int value)
{
obj.a = value;
}
and then use similar syntax to the getline() method on it:
setValueA(per, 36);
to achieve the same thing as per.a = 36, but with the benefits of encapsulation: if you later need to change the details of how reff stores its data (e.g. changing a and b to meaningful names), you only need to change the function implementation to use the new data members; all user code using this class will continue to work. If user code directly accessed the members, it would also need to be changed to use the new name.
Notice that setValueA() is accessing the member variables of the object it is passed; so calling it with per.a directly is not only unnecessary, but impossible:
setValueA(per.a, 36); // invalid: setValueA() requires a reff&, not an int
since the function itself tries to utilise the member a of the object it is passed, and an int does not have any members.
For the getline() call using a std::string, it has the same issue: for this function to work, it needs at the minimum:
read/write access to a pointer to the memory to store the data it reads (it may need to reallocate this if there's not enough space already allocated); and
the amount of memory pointed to the above, so it knows how much additional data it can store before it needs to allocate additional space.
So, given that getline() requires more than just a single intrinsic type in order to function, it should be clear why the parameter includes a string object rather than one of its specific member variable.
For additional examples, you should look up operator overloading, which can even let you do things like have per = 36; assign a value to per.a.
Here's a self-contained example using overloaded operators on a slightly modified version of your reff class. The comments try to explain what's going on, and should give you terms you can search for - this stuff is all pretty basic C++ and should be covered in any tutorial series.
#include <iostream>
class Reff
{
public:
int a;
float b; // changed the data type to illustrate overloading the = operator
// operator= will be called if we try to assign to a an object of this class;
// this version of the function accepts an integer value
Reff& operator= (int intval)
{
a = intval;
return *this;
}
// another operator=, this one accepting a float value as the parameter
Reff& operator= (float floatval)
{
b = floatval;
return *this;
}
};
// operator+ will be called if we try to add a value to this object;
// I'm only defining this one which accepts an int value
int operator+ (Reff const& reff, int intval)
{
return reff.a + intval;
}
// an overload of the operator<< function, which accepts a reference to
// an instance of a Reff, along with the output stream parameter.
std::ostream& operator<< (std::ostream& stream, Reff const& reff)
{
return stream << "[a:" << reff.a << " b:" << reff.b << "]";
}
int main()
{
// create an instance of our class
Reff per;
// assign the instance 42 (an integer value) - this will use the integer
// overload of the operator= we defined
per = 42;
// assign it a floating point value - this will use the float overload
// of the operator=. Note that if we didn't define a float-specific overload,
// the compiler would probably truncate the value to an integer and use our
// integer version instead - possibly with a warning, possibly silently,
// depending on your compiler settings.
per = 3.14159f;
// output the object; this will use the overload of the operator<< function
// that we created, which accepts our Reff object
std::cout << per << std::endl;
// output the result of adding 58 to our object; this will use the operator+
// overload which accepts an integer
std::cout << "per + 58 = " << (per + 58) << std::endl;
}
Here you can get output directly through
cout << "I like " << mystr << " too!\n";
because operator << is overridden in string Class.
like:
ostream& operator << (ostream& OS, MyString & S)
{
OS << S.get_string();
return OS;
}
Check whole implementation : http://www.cplusplus.com/forum/beginner/15396/
Consider the following snippet of c++ and the output below it.
#include <iostream>
using namespace std;
class One {
public:
One(int num);
One();
~One();
private:
int number;
};
One::One(int num) {
number = num;
cout << "One constructor number = " << number << endl;
}
One::One() {
number = 0;
cout << "default One constructor\n";
}
One::~One() {
cout << "One destructor. number = " << number << endl;
number = 0;
}
int main() {
One uno;
uno = One(2);
return 0;
}
default One constructor
One constructor number = 2
One destructor. number = 2
One destructor. number = 2
Notice the replication of the last line. I understand (& hate) why the default constructor is called by the first line in main, but the destructor for that instance is never called. Instead the destructor for the second instance is implicitly called twice. Why? And how is the variable 'number' able to persist at number=2 ? The destructor set it to 0. It's like the garbage collector is trying to delete the instance created by the default constructor but hitting an old copy of the 2nd. This is a trivial example but it's a real problem when it comes time to delete pointers.
One uno; // Create a default One instance - default constructor called.
uno = One(2); // Create a temporary One instance - number constructor called and prints 2.
// Assign temporary to uno - uno now has the number 2.
// Destroy temporary One instance - destructor called and prints 2.
return 0;
// uno destroyed. It has the number 2, so this also prints 2.
Or, in terms of the output you saw:
default One constructor // from uno construction
One constructor number = 2 // from temporary One(2) construction
One destructor. number = 2 // from temporary One(2) destruction
One destructor. number = 2 // from uno destruction (since number has changed)