Looks like it.
Looks like it.
Look up a C++ Reference and learn How To Ask Questions The Smart WayOriginally Posted by Bjarne Stroustrup (2000-10-14)
I don't know how can I print tracks without adding them first. (first point)
I think that you forget adding the implemenation of XmusicCd class, I add only the setter.
As the cd lenght would be calculated later, I removed from the constructor, and I didn't implement the function.
My current code:
Code:#include <iostream> #include <vector> #include <string> //using namespace std; // You may not modify XTrackInfo class XTrackInfo { std::string t_trackName; int t_length; public: XTrackInfo(); XTrackInfo(std::string trackName, int tLength); void setTrackName(std::string trackName); void setTrackLength(int tLength); const std::string& GetTrackName() const; int GetTrackLength() const; }; XTrackInfo::XTrackInfo() {} XTrackInfo::XTrackInfo(std::string trackName, int tLength) :t_trackName(trackName), t_length(tLength) {} const std::string &XTrackInfo::GetTrackName() const { return t_trackName; } int XTrackInfo::GetTrackLength() const { return t_length; } void XTrackInfo::setTrackLength(int tLength) { t_length = tLength; } void XTrackInfo::setTrackName(std::string trackName) { t_trackName = trackName; } class XMusicCd { private: // You may not modify these member variables std::string m_Author; std::vector<XTrackInfo> m_TrackInfo; public: // You may not modify these member functions XMusicCd(); XMusicCd(std::string Author, std::vector<XTrackInfo> Tracks); void SetAuthor(std::string Author); const std::string& GetAuthor() const; int GetLength() const; void AddTrack(XTrackInfo NewTrack) {} // Left incomplete on purpose; // you will implement it later // Add additional functions to this class as necessary to make it compile. }; XMusicCd::XMusicCd(){} XMusicCd::XMusicCd(std::string Author, std::vector<XTrackInfo> trackinfo) :m_Author(Author), m_TrackInfo(std::move(trackinfo)) { } const std::string& XMusicCd::GetAuthor() const{ return m_Author; } void XMusicCd::SetAuthor(std::string Author){ m_Author = Author; } void PrintCdContents(const XMusicCd& Cd) { // Implement this function such that it compiles // Also, to be explicit, you may not add any tracks to the CD in here. // That is not the purpose of this function. // You may also not change the signature of the function. // You shall specifically not modify the CD object by calling any setters. std::cout << "cd author " << Cd.GetAuthor() << "\n"; // // } int main() { // You may not change this function XMusicCd Cd; PrintCdContents(Cd); }
That's fine. You only need to worry about how to actually do the printing. But I've added updated code below that I've run and compiled to ensure it works.
For now, just focus on how you would theoretically implement the print function. Then you can complete the AddTrack function and then compile and run the code to ensure it works as expected.Code:// You may not modify XTrackInfo class XTrackInfo { std::string m_TrackName; int m_Length; public: XTrackInfo() {} XTrackInfo(std::string TrackName, int Length): m_TrackName(std::move(TrackName)), m_Length(Length) {} void SetTrackName(std::string TrackName) { m_TrackName = std::move(TrackName); } void SetTrackLength(int Length) { m_Length = Length; } const std::string& GetTrackName() const { return m_TrackName; } int GetTrackLength() const { return m_Length; } }; class XMusicCd { private: // You may not modify these member variables std::string m_Author; std::vector<XTrackInfo> m_TrackInfo; public: // You may not modify these member functions XMusicCd() {} XMusicCd(std::string Author, std::vector<XTrackInfo> Tracks): m_Author(std::move(Author)), m_TrackInfo(std::move(Tracks)) {} void SetAuthor(std::string Author) { m_Author = std::move(Author); } const std::string& GetAuthor() const { return m_Author; } int GetLength() const; // Left incomplete on purpose; you will implement it later void AddTrack(XTrackInfo NewTrack); // Left incomplete on purpose; you will implement it later // Add additional functions to this class as necessary to make it compile. }; void PrintCdContents(const XMusicCd& Cd) { // Implement this function such that it compiles // Also, to be explicit, you may not add any tracks to the CD in here. That is not the purpose of this function. You may also not change the signature of the function. // You shall specifically not modify the CD object by calling any setters. } int main() { // You may not change this function XMusicCd MyCd; MyCd.SetAuthor("Hello World"); MyCd.AddTrack(XTrackInfo("This is a test", 100)); MyCd.AddTrack(XTrackInfo("This is a test 2", 200)); PrintCdContents(MyCd); }
I would expect the code to print something like
when it's finished, but you don't need to actually make sure it prints it exactly like this. This is just a guideline.Code:Author: Hello World Track Info: Track #1 - Name: This is a test - Length: 100 Track #2 - Name: This is a test 2 - Length: 200
I think that I'm not thinking properly.
I want add a Newtrack to the CD object. The AddTrack receives a NewTrack as value. If the value is created on main using the overload constructor, NewTrack will contain the name and lenght. It won't need any setter.
But the code doesn't compile:
undefined reference to `XMusicCd::AddTrack(XTrackInfo)'
Should I add pass as refrence myCD object to the addTrack function?
Code:#include <iostream> #include <vector> #include <string> // You may not modify XTrackInfo class XTrackInfo { std::string m_TrackName; int m_Length; public: XTrackInfo() {} XTrackInfo(std::string TrackName, int Length): m_TrackName(std::move(TrackName)), m_Length(Length) {} void SetTrackName(std::string TrackName) { m_TrackName = std::move(TrackName); } void SetTrackLength(int Length) { m_Length = Length; } const std::string& GetTrackName() const { return m_TrackName; } int GetTrackLength() const { return m_Length; } }; class XMusicCd { private: // You may not modify these member variables std::string m_Author; std::vector<XTrackInfo> m_TrackInfo; public: // You may not modify these member functions XMusicCd() {} XMusicCd(std::string Author, std::vector<XTrackInfo> Tracks): m_Author(std::move(Author)), m_TrackInfo(std::move(Tracks)) {} void SetAuthor(std::string Author) { m_Author = std::move(Author); } const std::string& GetAuthor() const { return m_Author; } int GetLength() const; // Left incomplete on purpose; you will implement it later void AddTrack(XTrackInfo NewTrack); // Left incomplete on purpose; you will implement it later // Add additional functions to this class as necessary to make it compile. }; void AddTrack(XTrackInfo NewTrack){ std::cout << " " << NewTrack.GetTrackName(); } void PrintCdContents(const XMusicCd& Cd) { // Implement this function such that it compiles // Also, to be explicit, you may not add any tracks to the CD in here. That is not the purpose of this function. You may also not change the signature of the function. // You shall specifically not modify the CD object by calling any setters. std::cout << "Author : " << Cd.GetAuthor() << "\n"; std::cout << "\n" << std::endl; std::cout << "Track Info" << std::endl; } int main() { // You may not change this function XMusicCd MyCd; MyCd.SetAuthor("Hello World"); MyCd.AddTrack(XTrackInfo("This is a test", 100)); //MyCd.AddTrack(XTrackInfo("This is a test 2", 200)); PrintCdContents(MyCd); }
Last edited by marcoesteves; 08-17-2014 at 08:25 AM.
This is a design question. If you remove the setter, it is impossible to change the object after it has been created. This has its advantages and disadvantages.
The biggest disadvantage is that you need all the necessary information before creating the object. For example, if you have a global XTrackInfo object, but you get the required information necessary to initialize the object later (say, by asking the user), then you have a problem: the object must be initialized as it is created and cannot be modified later. The usual solution to that is to make a pointer or use some helper class such as std::optional or boost::optional to be able to initialize the object later. Calling new has overhead which you may or may not want to pay for. std::optional is not supported by all compilers yet.
Another disadvantage is that you need to specify all information in the constructor. Sometimes you don't want to specify all information, and with setters, you can selectively pick what you want to set.
Setters fixes these problems but also creates longer, more verbose code (calling a setter for each property). But it also means your object can end up in various partial states, so you have to ensure that all member functions behave correctly under all circumstances. For example, if the author is set, but not the length, or if neither length nor author is set. You can also push the responsibility on the user of the object, but that can cause more bugs in the program.
So it's a tradeoff, and as such, it's also a design decision. You are going to have pick a way or a hybrid way and experiment with them and pick the one that works best for you.
You declared AddTrack as a global function rather than a function of XMusicCd.But the code doesn't compile:
undefined reference to `XMusicCd::AddTrack(XTrackInfo)'
First, you shall not modify the function prototype, as explicitly stated.Should I add pass as refrence myCD object to the addTrack function?
But, if you were allowed to modify it, give me your reasoning. Why do you want to pass MyCd to AddTrack?
AddTrack must be a XmusicCd function, I moved into.
Howevver I don't understand a thing. The class MusicCD receives a vector of Tracks, but addTrack only receives one Track Object.
I tried push_back the vector, I'm not realising what it should happen. Probably is obvious.
It is incorrect pass MyCD to AddTrack if AddTrack is a function of the XmusicCd Class.
In general passing class objects by reference is usefull when we want to change attribute values on the original class object.
There is a reason for that.
You can only call a constructor once, so it must take all the tracks to add immediately. Hence, it takes a collection of tracks.
The setter can be called multiple times, so it more common to make it take one track instead of a collection. If the user wants to add multiple, they can use a loop. It can also be more efficient than creating a new vector, allocating memory and putting objects into there which have to be taken out later.
You could add a convenience function that takes a collection too, but we can discuss this later.
The next step after getting it to compile is to debug is. You will find out whether push_back is correct or not then.
What you say is true, but if AddTrack is global, how can it add a track to the class when there's no way to access its internal storage of the tracks? The thing is that it makes no sense. AddTrack is strongly coupled with the internals of the class. Therefore, it should be a member, because otherwise, you are exposing the innards of the class, which is bad. Exposing them means that code that rely on them break when the innards of the class change, and we want to avoid that. So generally, the public functions should not change, so that code that uses the class don't change if the class changes.It is incorrect pass MyCD to AddTrack if AddTrack is a function of the XmusicCd Class.
In general passing class objects by reference is usefull when we want to change attribute values on the original class object.
I partially understood.
If I add 2 mycd track objects at main, it will be stored 2 objects. So at this time, I don't need to create an addTrack function to print them.
However, i dindn't figure it out how can I print the content of the track.
No, the tracks objects will be stored inside the CD class. How it does that is an implementation detail (but why do you think there's a vector there?).
What did you try and why didn't it work?However, i dindn't figure it out how can I print the content of the track.
At main we're using the overload constructor. the overloaded constructor requires a vector type (I think so).
Directly printed the trackinfo object.
I've tried create an addtrack function too, but I didn't figure out how to append the vector.
I Think that I should focus at 1 problem each time, to solve the problem
Last edited by marcoesteves; 08-17-2014 at 04:54 PM.
Okay, but heh, I don't know where we're going with this.
Well, that's obviously not going to fix it since you need to print a CD, not a track (but a CD might print all its tracks).Directly printed the trackinfo object.
If you don't know how to append to a vector, you can just try a simple example:I've tried create an addtrack function too, but I didn't figure out how to append the vector.
Code:std::vector<int> v; // Add stuff to vector for (auto && e : v) std::cout << e << "\n";
I don't like PMs for things like this because you are depriving the world of learning from your confusion.Originally Posted by marcoesteves
Anyway, to correct your misunderstandings or help you on your way, I really need to see what you're struggling with. For example, what is your current attempt at the Print function? Why does it not work? Why have you implemented it the way you've done? Only by understanding how you think can I correct what is wrong.
To implement the code that prints the object, you don't need the AddTrack member function. In this you are correct. To compile the code, you need the AddTrack member function.
So yes, the idea was that you focused on creating an implementation for printing the object and only after you've finished that, should you focus on implement the AddTrack function. When you've implemented that, you can compile and run your code to ensure it's correct.
Ok. It's hard.
I'll try to explain in pieces as I'm understanding the problem.
At main:
We aren't using the overloaded constructor. So, to have attributes we must "set".Code:XMusicCd MyCd;
So the 2nd step is:
Everything is ok.Code:MyCd.SetAuthor("Hello World");
Then we have to addTracks (a cd object has a track vector)
However you wrote:Code:XMusicCd(std::string Author, std::vector<XTrackInfo> Tracks) :
So, my AddTrack function as a XTrackInfo object. But, Cd doesn't have a Vector of tracks?Code:MyCd.AddTrack(XTrackInfo("This is a test", 100));
Since we're using the overloaded constructor of XTrackInfo we don't need to set anything.
However, I'm not figuring out how to code the addTrack function.
To print all of cd attributes, now I think that I need to have the addTrack function working
Current (messing) code:
Code:#include <iostream> #include <vector> #include <string> // You may not modify XTrackInfo class XTrackInfo { std::string m_TrackName; int m_Length; public: XTrackInfo() {} XTrackInfo(std::string TrackName, int Length): m_TrackName(std::move(TrackName)), m_Length(Length) {} void SetTrackName(std::string TrackName) { m_TrackName = std::move(TrackName); } void SetTrackLength(int Length) { m_Length = Length; } const std::string& GetTrackName() const { return m_TrackName; } int GetTrackLength() const { return m_Length; } }; class XMusicCd { private: // You may not modify these member variables std::string m_Author; std::vector<XTrackInfo> m_TrackInfo; public: // You may not modify these member functions XMusicCd() {} XMusicCd(std::string Author, std::vector<XTrackInfo> Tracks): m_Author(std::move(Author)), m_TrackInfo(std::move(Tracks)) {} void SetAuthor(std::string Author) { m_Author = std::move(Author); } const std::string& GetAuthor() const { return m_Author; } int GetLength() const; // Left incomplete on purpose; you will implement it later // void AddTrack(XTrackInfo NewTrack); // Left incomplete on purpose; you will implement it later void AddTrack(XTrackInfo NewTrack){ } // Add additional functions to this class as necessary to make it compile. }; void PrintCdContents(const XMusicCd& Cd) { // Implement this function such that it compiles // Also, to be explicit, you may not add any tracks to the CD in here. That is not the purpose of this function. You may also not change the signature of the function. // You shall specifically not modify the CD object by calling any setters. //Cd. std::cout << "Author : " << Cd.GetAuthor() << "\n"; std::cout << "\n" << std::endl; std::cout << "Track Info" << std::endl; // for (unsigned int i=0; i< 2; i++ ){ // } //std::cout << " " << } int main() { // You may not change this function XMusicCd MyCd; MyCd.SetAuthor("Hello World"); MyCd.AddTrack(XTrackInfo("This is a test", 100)); MyCd.AddTrack(XTrackInfo("This is a test 2", 200)); PrintCdContents(MyCd); }
Yes, it does have a vector to store tracks internally. It needs to store all individual tracks and a vector is good for that.
But going back to my other example:
Can you figure out how to make this code printCode:std::vector<int> v; // Add stuff to vector for (auto && e : v) std::cout << e << "\n";
1
2
3
? Basically the code simply prints all the elements in the vector (it's a standard range for-loop over the vector), so you just need to add the elements to the vector.
I think it would be better to learn how to use vectors since you will need that to implement your AddTrack function.
Take a look at the reference for std::vector: std::vector - cppreference.com
Learning to read and understand documentation would serve you well, so it will be a small exercise to read the documentation and figure out how a vector works before you implement AddTrack.
I will also admit, that due to the constructor, there is another way to create the Music CD object, but I'm not going to provide that code since it will spoil some things on how to work with vectors. I'm sure that once you figure out the example, you will be able to figure out how to call the other music cd constructor.