Hi all I am in Intro to Programming and am a little unsure about member initialization and default constructors. We are learning the basics of classes and structures but we haven't even gotten to constructor methods or inheritance yet, so I'm a little ahead of the class. I surfed the web and I couldn't find an exact answer to my question so I figured I would ask here:
class ProductionWorker : public Employee
{
private:
int shiftNum;
double hourlyPay;
public:
//constructor for ProductionWorker
ProductionWorker(int newShiftNum, double newHourlyPay) : Employee(getEmpName(), getEmpNum())
{
shiftNum=newShiftNum;
hourlyPay=newHourlyPay;
}
In this snippet the first problem that I ran into was I was getting an error that there was no default constructor for the class Employee and after some research I found out that if a class is inheriting another class, the inherited class needs to have a default constructor. I read a little more into member initialization and from my understanding, I can do away with the need for a default constructor of an inherited class if I just have the ProductionWorker constructor initialize the Employee constructor.
Is this correct?
The arguments that are passed into the Employee constructor are "getters" because I can't directly pass in the variables held in the Employee class because they are private, would this cause unforeseen problems?
Before you create a class, you cannot access its members. So Employee( getEmpName(), getEmpNum() ) makes no sense. You are supposed to pass those values into the constructor, and then later if you need them, call the accessors.
public ProductionWorker( string name, int num, int shiftNum, double pay ) :
Employee( name, num )
{
this->shiftNum = shiftNum;
this->hourlyPay = pay;
}
Inheritance is a is a relationship. When you create a ProductionWorker you are also creating a Employee. Since Employee only has a constructor that takes a name and number (I assume), those are usually passed into ProductionWorker so it can create the Employee correctly. As Noted below, there are alternatives, but this seems like the logical way in this scenario.
Base class do not need to have a default constructor. If they do not have a default constructor, each constructor of a derived class needs to explicit call one of the base class constructors from its member initializer list. However, you shouldn't attempt to use any member functions because the object isn't constructed, yet. You basically want to use the constructor arguments of the derived class to determine which values you want to pass to the base class.
In your specific example it looks as if the Employee base class wants to get a name and an employee number. You might want to pass them to your derived class in addition to the information need only by the derived object.
You understend it correctly I think but you've missused a notion.
Arguments of Employee class constructor can be it's setters, because they might allow you to set the private properties of base class.
A getter would allow you to get (no surprise) the value of private field.
By the way, constructor of inheriting class will always call the base class' constructors. Of course if the base class have constructor that accepts no arguments then there is no need to call it explicitly in inheriting class.
Imagine that you have classes:
class ColorCircle : public Circle{
string color;
ColorCircle (string c)
{
this.color = c;
}
}
and
class Circle {
double diameter;
Circle (double d)
{
this diameter = d;
}
}
If you want to create a ColorCircle you have to provide also the information about it's diameter but the constructor of ColorCircle does not have any place for this. Thats why constructor of ColorCircle should look like this:
ColorCircle (string c, double d) : Circle (d)
{
this.color = c;
}
And when you create a ColorCircle you just do:
new ColorCircle("red", 2.5);
The program takes care about passing the diameter value 2.5 to the proper base class constructor.
Related
I am wondering whether it makes sense to have a class without constructor if the derived classes have one. If not, is there a way of doing what I want differently?
My case is the following:
I want the users to only use the derived classes, but those have data members and methods in common.
EDIT: as default constructors exist for classes, it means that the user can always create an instance of Instrument directly, then how can I do what I want?
class instrument{
public:
double get_price();
std::string get_udl();
private:
double m_price;
std::string m_udl;
};
class stock : public instrument{
public:
double get_dividend();
private:
double m_dividend;
};
class option : public instrument{
public:
double get_strike();
private:
double m_strike;
};
I want the users to only use the derived classes, but those have data members and methods in common
Have your default (or any other) c'tor, but declare it with protected access. Now only derived classes may invoke it. Effectively making it usable only when inherited.
class instrument{
public:
double get_price();
std::string get_udl();
protected:
instrument() = default;
private:
double m_price;
std::string m_udl;
};
This also avoids the overhead associated with making a class abstract. If you don't need polymorphism, you shouldn't use it just to make a class usable only as a base class.
Have thought of Abstract class ?
An abstract class is a class that is declared abstract—it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed.
Isn't this what you are looking for ?
When there's no default constructor defined, the compiler will automatically generate one for you, doing nothing for members of basic types and calls the default constructor for members of struct/class types.
So the conclusion is, it makes no sense to have a class without any constructor because whenever you define an instance of that class you have to call at least one (more may be called with deligate construction).
Yes! Definitely it make sense. Because when user create the instance of derived class, first of all parent class's constructor will be called from within the derived class constructor. Even without you explicitly call it. And parent class's default constructor will be called even if you didn't create one. By default
public constructor with no parameter is present in every class
if it has no overridden constructor.
And yes all the public members of parent class will be present in derived class after creating derived class instance.
I've benn having a problem for a while, when I'm trying to inherit from a pure virtual class, when I make the constructor for the "son" classes I receive this error:
../src/Course.cpp:54:77: error: class ‘ElectiveCourse’ does not have any field named ‘_dptr’
And this happens for all of the Course Protected fields.
This is the structure:
Course.h:
class Course{
public:
virtual void reg(Student * s) = 0;
..
protected:
...
string _dptr;
...
};
and then:
class ElectiveCourse : public Course{
...
}
Course.cpp:
ElectiveCourse::ElectiveCourse(
string name,
int semester,
double minGrade
)
: _dptr("CS"), _name(name), _semester(semester), _minGrade(minGrade) {
}
Like the ElectiveCourse, I have two other classes that inherit from the Course class, and I'm getting the same error in all of them.
[EDIT] This only happens in the Constructor of them.
There is NO constructor in the Course class hence it is pure virtual.
In the other hand, I also have two classe: Student, and CSStudent : Student, where Student is also pure virtual and CSStudent inherit Student, and in this case there are no errors. I did the same exact thing in both of them.
What seems to be the problem?
I'm sorry for my grammar errors.
[EDIT]
added the Course.cpp part where I'm getting the error.
Thanks!
You cannot initialize member variables of one class in another class. If you want to initialize the member variables of Course in a constructor, you have to add a constructor to Course. You can make that constructor protected if you like.
The alternative (probably better) would be to change your design to make Course an interface.
You can't initialize the fields of your parent class in the subclass constructor. The reason for that is that the construction order includes the construction of base class before you can actually address its inner fields. And construction of the base requires construction of its inner fields. That said, to achieve what you need, you should create a constructor in your base class that accepts all of your parameters (name, semester etc.) and invoke this constructor from your subclass constructor:
Course::Course(string name,
int semester,
double minGrade):
_dptr("CS"),
_name(name),
_semester(semester),
_minGrade(minGrade){}
ElectiveCourse::ElectiveCourse(string name,
int semester,
double minGrade):
Course(name, semester, minGrade){}
How can I compute the value of a child class's member variable in it's constructor, and then pass on to the parent's constructor??
The motivation is that, if there's a lot of calculation in the parent class default constructor, then I don't want to have to do those calculation and only have them replaced by those computed by child class right after.
For example:
Car.h
class Car
{
public:
Car();
Car(double Price) ;
...
private:
double price;
double DetermineMarketPrice();
};
Car.cpp
Car::Car()
{
//some other long computation
price = DetermineMarketPrice();
}
Car::Car(double Price)
{
price = Price;
}
...
Porche.h
class Porche : public Car
{
public:
Porche();
...
private:
double price;
double discount;
double fee;
double DetermineMarketPrice();
double RetrieveFee();
double CheckDiscount();
...
};
Porche.cpp
Porche::Porche():Car(price)
{
discount = CheckDiscount();
fee = = RetrieveFee();
price = DetermineMarketPrice() * (1-discount) + fee;
}
In this case, the price of a Porche isn't known yet. It has to be calculated in the constructor. If I call the parent's constructor like this, seems like it would only pass the not-yet-initialized price.
What would be a good way to pass some value of member variables that can only be known at the end of the Child class initialization???
You can't do that, the base class constructors are executed first in the initialisation order, before data members are initialised and before the derived class constructor's body is executed. If these are costly calculations, the best thing to do may be moving them out of the constructor.
EDIT: There's technically a way to work around this problem, by creating a second constructor, or having a default constructor with a default parameter value, which can be used to stop the calculations in the base class, like so:
struct SkipCalculatePrice {};
class Car {
public:
Car();
protected:
Car(SkipCalculatePrice);
};
class Ferrari: public Car {
public:
Ferrari(): Car(SkipCaluclatePrice()) [...]
[...]
However, I personally would not recommend this as a good design practice. It is understood that one would want to avoid delayed initialization as an anti-pattern, however, for costly calculations, properly done lazy initailization might be the right answer:
class Car {
virtual double calculatePrice();
bool priceCalculated;
double price;
public:
double getPrice() {
if(!priceCaluclated) {
price = calculatePrice();
}
return price;
}
}
class Ferrari: public Car {
double calculatePrice();
};
A lot depends on the actual situation, but one frequent solution is to
offload all of the calculations into a static member, so you can write:
Porsche::Porsche()
: Car( calclulatePrice() )
{
// ...
}
This won't work if (as your example suggests) you first have to
calculate other member variables, before setting the variable in the
base class. For cases like the one you present, the simplest solution
is just to initialize the base class with 0, and then set the actual
value later.
More generally, I have to wonder about your design. It can't be right
that both the base class and the derived class have a member price.
In the most frequent use of inheritance, the base class will be
abstract, with no data members. But even when this is not the case, the
data members of the base class are not duplicated in the derived
classes: if the derived classes can set or change them in an arbitrary
way, they may be protected; otherwise, they are in the base class, and
only manipulated by functions in the base class (which may be called
from the derived class).
Just move the calculation code out of the constructor to a utility function such as CalculatePrice( ). Construct the object and then call this function.
Use an virtual method in the constructor of the parent to determine the price. Redefine this method in each child class.
Approach 1: Initialise through constructor of dervive class
class base {
protected:
int no;
public:
void showData() {
cout << no;
}
};
class der : public base {
public:
der(int _no) {
no = _no;
}
};
Approach 2: Initialise through constructor of base class
class base {
int no;
protected:
base(int _no) : no(_no){}
public:
void showData() {
cout << no;
}
};
class der : public base {
public:
der(int _no) : base(_no) {
}
};
client code:
der d(10);
d.showData();
Please let me know If there is other method
You should use the second approach, with one reason: if the base class member is private, approach one won't work. It's also strange to see a derived class initializing things that don't belong to it.
Each class ctor should initialise fields in that class. So the second variant.
Obviously the second option for various reasons:
Let constructor of a class do its task: Construction. Let every class initialize its own data members.
Data members may be private, and derived class may not have access to.
Option 1 would involve code maintenance for ALL derived classes, and this would definitely lead to bugs.
Option 1 is not good appraoch as far as encapulation is concerned.
I'd strongly opt for approach 2, as the constructor may also be more complex than just initializing variables. Additionally, private members in case cannot be set in der.
The second is the correct approach. It's always best to initialize with a constructor, that's what they are for. What would you do if you had more than one derived class? What if you wanted to create base class objects by themselves? Put the initalization code in the constructor, that's how C++ is designed to work.
Always use the ctor-initializer to initialize things. Because this is the only place where you can really initialize things. Writing no=no_ anywhere will assign to an already initialized variable. For UDTs this might be a big difference, for references this is not even possible, you always have to initialize them.
So also for uniformity, use the ctor-initalizer everywhere.
Say i create a derived class as below,
class CHIProjectData : public QObject
{
CHIProjectData(QMap<QString,QString> aProjectData,
CHIMetaData* apMetaData = 0,
QObject* parent = 0);
private:
QMap<QString,QString> m_strProjectData;
CHIAkmMetaData* m_pMetaData;
};
and i implement like,
CHIProjectData::CHIProjectData(QMap<QString,QString> aProjectData,
CHIMetaData* apMetaData,
QObject* aParent)
:m_strProjectData(aProjectData),
m_pMetaData(apMetaData),
QObject(aParent)
{
}
i know i initiate the member variables m_strProjectData, m_pMetaData in the constructor. but what does the last part "QObject(aParent)" do? does it create an object of base class and consider that as a member variable?
QObject(aParent) calls QObject's constructor with the aParent parameter. QObject is not a member variable in this case. It may seem like a subtle point, but its an important one because the way you access the properties and methods of a subobject requires different syntax than as for a member variable.
Here's an analogy to try to understand the difference between a subobject and a member variable.
In the movie "Batman: The Dark Night" there is a scene where Batman is pursuing the bad guy in his car. But the car becomes damaged and unusable, and he has to escape. At that point Batman pushes a button and part of the car detatches from the rest, becoming a motorcycle. This is kind of like a subobject. The car is a motorcycle.
Now consider the case of an RV towing a smaller vehicle, the likes of which are frequently seen on the highways of America. In this case, the RV has a vehicle. The vehicle is a member variable of the RV.
Essentially, that is what is happening under the hood. The base class parts of your object, like its data members, are called subobjects.
The notion of initializing a base as in QObject(aParent) is similar to initializing a member, but bases are always initialized first. Therefore, it would be clearer to list QObject before the members, so the list of initializers is in chronological order.
The order of initialization always follows the order the bases are named after class and the order the members are declared, no matter how the initializer sequence is written.
A class instance that is a base of a derived class is sometimes called a "base class subobject", so in some sense a base class is a distinct 'part' of your derived class.
In your constructor's initializer list, the QObject(aParent) is choosing how the base class is constructed. In this case a single parameter constructor is being used. If the base class were omitted from the initializer list of your derived class' constructor its default constructor would be used.
It's not strictly a member variable, although like a member variable it's a constituent part of your derived class along with any other base class subobjects and other members.
Not quite. It tells the base class's constructor what to do. Imagine this class:
class A
{
public:
A(int val)
: value(val)
{
}
protected:
int value;
};
To construct A, you have to pass an int. This is always true, even if you derive from it.
Say you are class B, which derives from A. You are an A, but you still have to tell the A part of your class how to construct itself:
class B : public A
{
public:
B()
: A(5)
{
}
int GetValue()
{
return value;
}
};
The members of A become your members, though, because you are an A.
In machine memory, the scenario is kind of how you described, but only in simple cases. It becomes more complicated with virtual functions, multiple inheritance, and virtual inheritance. If you stick to the is-a and has-a relationships, then you may avoid some headaches :)