Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game. |
Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
 |
04-12-2011, 08:20 PM
|
#1
|
LQ Newbie
Registered: Jul 2010
Posts: 12
Rep:
|
C++ Initialize Class Member Variables of Another Class Type
So I'm wondering how I can make a constructor for a class contain other class members.
Here's my constructor:
Course::Course()
{
courseCode = "";
section = "";
DaysOfWeek* daysMeets = new DaysOfWeek();
TimeInterval* timeMeets = new TimeInterval();
instructorName = "";
}
My private member variables for Course is:
string courseCode;
string section;
DaysOfWeek daysMeets;
TimeInterval timeMeets;
string instructorName;
Will my daysMeets private variable be initialized (which is what I want) or will it just create it's own NEW DaysOfWeek object that overrides my private member variable. I have a feeling it's the second, so my question is: what is the proper way to initialize a private member variable that is of another class type?
Unfortunately I can't test this for some time, and it's really bothering me. I've searched all over for the answer, it compiles of course, but I doubt it's doing what I want.
|
|
|
04-12-2011, 08:28 PM
|
#2
|
LQ Newbie
Registered: Jul 2010
Posts: 12
Original Poster
Rep:
|
Also, this compiles, but I'm not sure if this is what I'm looking for either, but it does seem much more like what I want:
daysMeets = DaysOfWeek();
timeMeets = TimeInterval();
Last edited by mirlin510; 04-12-2011 at 08:31 PM.
|
|
|
04-12-2011, 11:07 PM
|
#3
|
Senior Member
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379
Rep: 
|
daysMeets is a pointer to an object. So what you want is:
Code:
daysMeets = new DaysOfWeeks();
this will make your private member variable point to the newly created object. It will then hand over responsibility to the DaysOfWeeks class (specifically the constructor) to initialise this object.
What you had:
Code:
DaysOfWeeks * daysMeets = new DaysOfWeeks();
will hide the member variable with a local variable (which will then get lost once the constructor completes) and provide you with an object that you can no longer acess.
Last edited by graemef; 04-13-2011 at 07:33 AM.
|
|
|
04-13-2011, 06:33 AM
|
#4
|
Senior Member
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541
|
@ the OP --
Please be advised that the proper place to initialize class member data is not in the body of the constructor, but prior to it.
Code:
class Foo
{
public:
Foo();
private:
int value;
};
Foo::Foo()
: value(0) // initialize member data in this section
{
// once this point is reached, the object should hopefully be fully constructed.
}
For your code, it is unnecessary to initialize std::string objects since these already have a default constructor; thus the following would be appropriate:
Code:
Course::Course()
: daysMeets(new DaysOfWeek),
timeMeets(new TimeInterval)
{
}
|
|
|
04-13-2011, 07:25 AM
|
#5
|
Member
Registered: Mar 2009
Location: Rotterdam, the Netherlands
Distribution: Slackwarelinux
Posts: 716
Rep: 
|
You can also make multiple constructors by overloading them:
Code:
Course::Course()
{
courseCode = "";
section = "";
DaysOfWeek* daysMeets = new DaysOfWeek();
TimeInterval* timeMeets = new TimeInterval();
instructorName = "";
}
Course::Course(DaysOfWeek *meets)
{
courseCode = "";
section = "";
DaysOfWeek *daysMeets = meets;
TimeInterval *timeMeets = new TimeInterval();
instructorName = "";
}
Course::Course(DaysOfWeek *meets, TimeInterval *times)
{
courseCode = "";
section = "";
DaysOfWeek *daysMeets = meets;
TimeInterval *timeMeets = times;
instructorName = "";
}
You can then construct your class like this:
new Course(days, meets);
or
new Course(days);
or
new Course();
in case you constructed the other classes already, you can use their data in your constructor.
Last edited by Ramurd; 04-13-2011 at 07:27 AM.
|
|
|
04-13-2011, 07:42 AM
|
#6
|
LQ Guru
Registered: Dec 2007
Distribution: Centos
Posts: 5,286
|
Quote:
Originally Posted by mirlin510
My private member variables for Course is:
string courseCode;
string section;
DaysOfWeek daysMeets;
TimeInterval timeMeets;
string instructorName;
|
I think some of those answering earlier might have missed the detail that daysMeets and timeMeets are not pointers.
You have clearly implied that DaysOfWeek and TimeInterval both have default constructors. That means you don't need to initialize daysMeets nor timeMeets. The compiler takes care of that for you, just as it takes care of initializing the strings for you. So your Course constructor doesn't need to do anything at all.
Assuming Course is something like
Code:
class Course {
public:
Course();
private:
string courseCode;
string section;
DaysOfWeek daysMeets;
TimeInterval timeMeets;
string instructorName;
};
All you actually need for the constructor is
Code:
Course::Course() {}
A good constructor might be:
Code:
Course::Course() :
courseCode(),
section(),
daysMeets(),
timeMeets(),
instructorName()
{}
Each one of the lines in blue is individually optional (subject to having the , on all but the last one included and removing the : if you remove all those lines).
Those lines remind anyone reading your code that the default constructor is used for each of those members. If you leave the line out, the compiler still knows the default constructor is used.
If you wanted to use a non default constructor for any one of those members, you would fill in the constructor parameters in the ().
Quote:
Originally Posted by mirlin510
Also, this compiles, but I'm not sure if this is what I'm looking for either, but it does seem much more like what I want:
daysMeets = DaysOfWeek();
timeMeets = TimeInterval();
|
That would compile, and would get the job done. But it is doing a lot of throw away work:
The compiler inserts a call to the default constructor for each of those members because you didn't specify their construction. Then you specify that a temporary object of the same type be created with another call to the default constructor, then copied over the already initialized member with a call to the assignment operator. (The compiler might optimize away some of that extra nonsense, but you still shouldn't have coded it in the first place).
Last edited by johnsfine; 04-13-2011 at 08:05 AM.
|
|
|
04-13-2011, 08:02 AM
|
#7
|
LQ Newbie
Registered: Jul 2010
Posts: 12
Original Poster
Rep:
|
Quote:
Originally Posted by johnsfine
I think some of those answering earlier might have missed the detail that daysMeets and timeMeets are not pointers.
You have clearly implied that DaysOfWeek and TimeInterval both have default constructors. That means you don't need to initialize daysMeets nor timeMeets. The compiler takes care of that for you, just as it takes care of initializing the strings for you.
Assuming Course is something like
Code:
class Course {
public:
Course();
private:
string courseCode;
string section;
DaysOfWeek daysMeets;
TimeInterval timeMeets;
string instructorName;
};
A good constructor might be:
Code:
Course::Course() :
courseCode(),
section(),
daysMeets(),
timeMeets(),
instructorName()
{}
Each one of the lines in blue is individually optional (subject to having the , on all but the last one included and removing the : if you remove all those lines).
Those lines remind anyone reading your code that the default constructor is used for each of those members. If you leave the line out, the compiler still knows the default constructor is used.
If you wanted to use a non default constructor for any one of those members, you would fill in the constructor parameters in the ().
|
This is much more of what I'm looking for, but what if I overloaded a constructor and want to make my own DaysOfWeek/TimeInterval object equal to it and set my local variable to that new object? I guess I should not have used a default constructor as an example.
I currently have something like this in the other constructor:
Course::Course(string aCourseCode, string aSection, DaysOfWeek&
aDaysMeets, TimeInterval& aTimeMeets, string aInstructorName)
{
courseCode = aCourseCode;
section = aSection;
daysMeets = DaysOfWeek(aDaysMeets.get());
timeMeets = TimeInterval(aTimeMeets.getStart(),aTimeMeets.getEnd());
instructorName = aInstructorName;
}
Quote:
That would compile, and work get the job done. But it is doing a lot of throw away work:
The compiler inserts a call to the default constructor for each of those members because you didn't specify their construction. Then you specify that a temporary object of the same type be created with another call to the default constructor, then copied over the already initialized member with a call to the assignment operator. (The compiler might optimize away some of that extra nonsense, but you still shouldn't have coded it in the first place).
|
What is the proper way to do this for a non-default constructor then if I have my own DaysOfWeek object being passed into the constructor?
Last edited by mirlin510; 04-13-2011 at 08:06 AM.
|
|
|
04-13-2011, 08:52 AM
|
#8
|
LQ Guru
Registered: Dec 2007
Distribution: Centos
Posts: 5,286
|
Quote:
Originally Posted by mirlin510
Course::Course(string aCourseCode, string aSection, DaysOfWeek&
aDaysMeets, TimeInterval& aTimeMeets, string aInstructorName)
{
courseCode = aCourseCode;
section = aSection;
daysMeets = DaysOfWeek(aDaysMeets.get());
timeMeets = TimeInterval(aTimeMeets.getStart(),aTimeMeets.getEnd());
instructorName = aInstructorName;
}
|
The better way to do that is:
Code:
Course::Course(string const& aCourseCode,
string const& aSection,
DaysOfWeek& aDaysMeets,
TimeInterval& aTimeMeets,
string const& aInstructorName
) :
courseCode( aCourseCode ),
section( aSection ),
daysMeets( aDaysMeets.get() ),
timeMeets( aTimeMeets.getStart(),aTimeMeets.getEnd() ),
instructorName(aInstructorName )
{}
Comments:
1) Passing strings by const& is generally better than by value (and definitely better in this example), so I made that change. But this change is independent of the overall change in the structure of the constructor.
2) The sequence of the initialization list between the ) : and the {} should match the sequence that the members are declared in the definition of the class. I don't know what sequence you declared them in, so I just kept the sequence from your version of the constructor. Note the sequence of parameters to your constructor is whatever you want. The compiler does not relate it to the sequence of members initialized from those parameters.
3) I see you passed two objects by & rather than const&. I didn't change that because I don't know whether your get() methods are const methods. But it looks like a situation where the get() methods should have been const and the parameters passed to Course() should have been const&.
4) Your code makes me wonder what DaysOfWeek(aDaysMeets.get()) is doing. It looks like the intent is to copy the object. Is there a good reason that is not done with a direct copy? In your form of the constructor that would be
daysMeets = aDaysMeets;
In my form of the constructor, that would be
daysMeets( aDaysMeets ),
5) As I explained before, your version of the code looks like it would work as long as DaysOfWeek and TimeInterval have default constructors. But your code does a lot of excess work: calling the default constructor that you don't actually want, then making a temporary object with the correct constructor, then copying the temporary object using the assignment operator. In a well written project, I expect DaysOfWeek and TimeInterval would not have default constructors, because neither object seems to make any sense prior to having contents. If they don't have default constructors then your form of the Course() constructor can't work. That is why it is better to use the form dwhitney67 suggested and I have been repeating. This form avoids the implied call to default constructors that you don't want invoked.
Last edited by johnsfine; 04-13-2011 at 09:17 AM.
|
|
|
04-13-2011, 08:58 AM
|
#9
|
LQ Newbie
Registered: Jul 2010
Posts: 12
Original Poster
Rep:
|
Quote:
Originally Posted by johnsfine
The better way to do that is:
Code:
Course::Course(string const& aCourseCode,
string const& aSection,
DaysOfWeek& aDaysMeets,
TimeInterval& aTimeMeets,
string const& aInstructorName
) :
courseCode( aCourseCode ),
section( aSection ),
daysMeets( aDaysMeets.get() ),
timeMeets( aTimeMeets.getStart(),aTimeMeets.getEnd() ),
instructorName(aInstructorName )
{}
|
Excellent! Thank you very much for your help.
|
|
|
04-13-2011, 11:46 AM
|
#10
|
LQ Newbie
Registered: Jul 2010
Posts: 12
Original Poster
Rep:
|
Quote:
Your code makes me wonder what DaysOfWeek(aDaysMeets.get()) is doing. It looks like the intent is to copy the object. Is there a good reason that is not done with a direct copy? In your form of the constructor that would be
daysMeets = aDaysMeets;
In my form of the constructor, that would be
daysMeets( aDaysMeets ),
|
I should probably be doing a direct copy, yes. I have changed my code to initialize before the brackets as well.
|
|
|
All times are GMT -5. The time now is 01:23 PM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|