LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
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



Reply
 
Search this Thread
Old 04-12-2011, 09:20 PM   #1
mirlin510
LQ Newbie
 
Registered: Jul 2010
Posts: 12

Rep: Reputation: 0
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.
 
Old 04-12-2011, 09:28 PM   #2
mirlin510
LQ Newbie
 
Registered: Jul 2010
Posts: 12

Original Poster
Rep: Reputation: 0
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 09:31 PM.
 
Old 04-13-2011, 12:07 AM   #3
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
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 08:33 AM.
 
Old 04-13-2011, 07:33 AM   #4
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,523

Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
@ 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)
{
}
 
Old 04-13-2011, 08:25 AM   #5
Ramurd
Member
 
Registered: Mar 2009
Location: Rotterdam, the Netherlands
Distribution: Slackwarelinux
Posts: 555

Rep: Reputation: 75
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 08:27 AM.
 
Old 04-13-2011, 08:42 AM   #6
johnsfine
Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,144

Rep: Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127
Quote:
Originally Posted by mirlin510 View Post
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 View Post
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 09:05 AM.
 
Old 04-13-2011, 09:02 AM   #7
mirlin510
LQ Newbie
 
Registered: Jul 2010
Posts: 12

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by johnsfine View Post
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 09:06 AM.
 
Old 04-13-2011, 09:52 AM   #8
johnsfine
Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,144

Rep: Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127Reputation: 1127
Quote:
Originally Posted by mirlin510 View Post
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 10:17 AM.
 
Old 04-13-2011, 09:58 AM   #9
mirlin510
LQ Newbie
 
Registered: Jul 2010
Posts: 12

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by johnsfine View Post
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.
 
Old 04-13-2011, 12:46 PM   #10
mirlin510
LQ Newbie
 
Registered: Jul 2010
Posts: 12

Original Poster
Rep: Reputation: 0
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.
 
  


Reply

Tags
c++, initialize, member, private, variables


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
C++, How to initialize nested class constructor?? jayasekar Programming 4 04-02-2010 01:18 PM
How to initialize a static array of a class in a static member function lali.p Programming 9 02-16-2008 10:27 AM
C++ templated Node class: pointers to different instantated class types jhwilliams Programming 3 08-20-2007 07:20 PM
Which C++ editor in Linux has the class view/class browser feature imaginationworks Programming 7 05-22-2006 12:09 AM


All times are GMT -5. The time now is 01:58 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration