I know, I'm stubborn, but there is my updated code with printing enable.
I've got some doubts. I think should be a smarter way to use the iterators. For instance without creating the:Code:#include <iostream> #include <vector> #include <string> 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; } const std::vector<XTrackInfo>& GetTracks() const { return m_TrackInfo;} int GetLength() const {} void AddTrack(XTrackInfo NewTrack){ m_TrackInfo.emplace_back(std::move(NewTrack)); } }; void PrintCdContents(const XMusicCd& Cd) { std::cout << "Author : " << Cd.GetAuthor() << "\n"; std::cout << "\n" << std::endl; std::cout << "Track Info" << std::endl; std::vector<XTrackInfo> tracks = Cd.GetTracks(); for (std::vector<XTrackInfo>::const_iterator it = tracks.begin(); it != tracks.end(); ++it) { std::cout << it->GetTrackName() << std::endl; std::cout << it-> GetTrackLength() << 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)); // MyCd.GetLength(); PrintCdContents(MyCd); }
Is there a way to pass the reference instead the object?Code:std::vector<XTrackInfo> tracks = Cd.GetTracks();
It remains one function to code
This is function is inside XMusicCD class . So, if I were able to use the reference instead the object, i can use iterators to sum all of lengths of tracks which belong to the particular Cd object. Right?Code:int GetLength() const {}
I want to avoid using static variables. They are easy to use, but bad programming practice.
Use a reference:
Or better yet,Code:std::vector<XTrackInfo>& tracks = Cd.GetTracks();
Code:auto && tracks = Cd.GetTracks();Since you wish to learn about C++11...Code:for (std::vector<XTrackInfo>::const_iterator it = tracks.begin(); it != tracks.end(); ++it) { std::cout << it->GetTrackName() << std::endl; std::cout << it-> GetTrackLength() << std::endl; }
Code:for (auto && elem : tracks) { std::cout << elem.GetTrackName() << std::endl; std::cout << elem.GetTrackLength() << std::endl; }
C++11 has an easier implemenation, but harder to understand 1st time.
Now, I'm concerned about:
This functions must get the sum of all lenghts.Code:int GetLength() const;
First at all, how do you (Elysia) declare as const ? If the value changes, shouldn't have const?
This is a mutation function of XMusicCD class. I'm not figuring out how can I access the TracKObjects, if they aren't created at this point (If I'm not wrong).
I'm assuming that you are correct, but I think this function can be global and use static members. On the other hand, static variables aren't a good programming pratice.
On the contrary,
auto && tracks = Cd.GetTracks();
means simply "hey, compiler, deduce the type for me so I don't have to spell it."
Two ampersands instead of one has to do with r-value references, so just take it as standard practice when it comes to using the keyword auto. auto and double ampersands go together. Look into "universal references" if you want to know more.
Now this:
for (auto && elem : tracks)
simply means: hey, give me every element in tracks and for each element in tracks, store a reference to it in elem.
Plain, simple, intuitive.
The function is const, not the variable. That means the function cannot change any member variables or call non-const functions. Look up the meaning of const.Now, I'm concerned about:
This functions must get the sum of all lenghts.Code:int GetLength() const;
First at all, how do you (Elysia) declare as const ? If the value changes, shouldn't have const?
No, it's not a mutation function. Getting the length does not require "mutating" any class state.This is a mutation function of XMusicCD class.
A global function with static members? I don't see how that would ever work, so if you think you can pull it off, then go ahead and try. You should see why it can't be pulled off.I'm not figuring out how can I access the TracKObjects, if they aren't created at this point (If I'm not wrong).
I'm assuming that you are correct, but I think this function can be global and use static members. On the other hand, static variables aren't a good programming pratice.
You're right. The function can be global, but I want you think about member state (i.e. member variables and *this).
I think that I'm understanding. However I've searched on references about *this pointer and I'm not figuring out how to using. I've only found examples which not fit. The most interesting that I found was:
C++ this Pointer
GetLenght "needs" to access the value of trackinfo lenght.
In XMusicCD it's possible access the accessor functions of XTrackInfo. However, I think that we cannot use iterators since we're not sure if there is an object.
Or on the other hand it can be possible use an argument in GetLenght;
There is my code updated with a global function:
Code:#include <iostream> #include <vector> #include <string> 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; } const std::vector<XTrackInfo>& GetTracks() const { return m_TrackInfo;} // int GetLength(XMusicCd Cd) const{ // } void AddTrack(XTrackInfo NewTrack){ m_TrackInfo.emplace_back(std::move(NewTrack)); } }; void CalcTotalLen(const XMusicCd& Cd){ int sum=0; auto && MyTracks = Cd.GetTracks(); for (auto && elem : MyTracks) { sum+= elem.GetTrackLength(); } std::cout << "total len: "<< sum << std::endl; } void PrintCdContents(const XMusicCd& Cd) { std::cout << "Author : " << Cd.GetAuthor() << "\n"; std::cout << "\n" << std::endl; std::cout << "Track Info" << std::endl; //std::vector<XTrackInfo> tracks = Cd.GetTracks(); auto && MyTracks = Cd.GetTracks(); // for (std::vector<XTrackInfo>::const_iterator it = tracks.begin(); it != tracks.end(); ++it) { // std::cout << it->GetTrackName() << std::endl; // std::cout << it-> GetTrackLength() << std::endl; // } for (auto && elem : MyTracks) { std::cout << elem.GetTrackName() << std::endl; std::cout << elem.GetTrackLength() << 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); CalcTotalLen(MyCd); }
Look at this code:
Run it. Print it. Examine it.Code:class A { public: void foo() { std::cout << "My address is " << this << ", and my bar value is " << bar << "\n"; } // this->bar also works int bar = 0; }; int main() { A A1, A2; A1.bar = 10; A2.bar = 20; std::cout << "Address of A1 is " << &A1 << ", and its bar value is " << A1.bar << "\n"; A1.foo(); std::cout << "Address of A2 is " << &A2 << ", and its bar value is " << A2.bar << "\n"; A2.foo(); }
You see that class A has a variable bar. But as we have TWO A objects, we have TWO bar variables. So how does A::foo know which bar variable whose value it should print? Simply put, the "this" keyword.
If you run it, you will see that "this" equals the value of the address of the object. In other words, we can see
A1.foo();
as being the same as
foo(&A1);
Which leads us to that in reverse, that means
foo(&A1);
is the same as
A1.foo();
So you wrote
auto && MyTracks = Cd.GetTracks();
This, then, can implicitly be thought of as
auto && MyTracks = GetTracks(&Cd);
Which implies that in XMusicCd::GetTracks, "this" == &Cd.
So I ask you: in XMusicCd::GetLength(), how would you acquire the tracks object?
I've updated my code and I have a few questions:
I want to implement a simple counter.Code:#include <iostream> #include <vector> #include <string> 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; } const std::vector<XTrackInfo>& GetTracks() const { return m_TrackInfo;} void AddTrack(XTrackInfo NewTrack){ m_TrackInfo.emplace_back(std::move(NewTrack)); } int GetLenght() const{ int sum=0; auto && MyTracks = this->GetTracks(); for (auto && elem : MyTracks) { sum+= elem.GetTrackLength(); } return sum; } }; class XCollection { private: std::vector <XMusicCd> m_cdCollection; public: XCollection(){} XCollection(std::vector <XMusicCd> CdCollection): m_cdCollection(std::move(CdCollection)) {} const std::vector <XMusicCd>& GetCds() const {return m_cdCollection;} void addCD(XMusicCd NewCD){ m_cdCollection.emplace_back(std::move(NewCD)); } }; void CalcTotalLen(const XMusicCd& Cd){ int sum=0; auto && MyTracks = Cd.GetTracks(); for (auto && elem : MyTracks) { sum+= elem.GetTrackLength(); } std::cout << "total len: "<< sum << std::endl; } void PrintCollectionContents(const XCollection& Collection){ std::cout << "Cd number : " << "1" << "\n"; std::cout << "Cd info : " << std::endl; auto MyCds = Collection.GetCds(); for(auto && elem: MyCds){ std::cout << elem.GetAuthor() << std::endl; //How can I acess the tracks of the particular cd ? } } void PrintCdContents(const XMusicCd& Cd) { std::cout << "Author : " << Cd.GetAuthor() << "\n"; std::cout << "\n" << std::endl; std::cout << "Track Info" << std::endl; //std::vector<XTrackInfo> tracks = Cd.GetTracks(); auto && MyTracks = Cd.GetTracks(); // for (std::vector<XTrackInfo>::const_iterator it = tracks.begin(); it != tracks.end(); ++it) { // std::cout << it->GetTrackName() << std::endl; // std::cout << it-> GetTrackLength() << std::endl; // } for (auto && elem : MyTracks) { std::cout << elem.GetTrackName() << std::endl; std::cout << elem.GetTrackLength() << 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); CalcTotalLen(MyCd); std::cout << "total cd lenght: " << MyCd.GetLenght()<< std::endl; XCollection MyCollection; MyCollection.addCD(MyCd); PrintCollectionContents(MyCollection); }
When I add a cd to a particular collection, automatcly it makes sense it has a number.
Do I need to use a static or global variable? Anytime that I emplace another cd I wanna count +1.
Another question:
I want to access the tracks of one particular cd. Can I use another for? I don't know which is the best way.
Code:void PrintCollectionContents(const XCollection& Collection){ std::cout << "Cd number : " << "1" << "\n"; std::cout << "Cd info : " << std::endl; auto MyCds = Collection.GetCds(); for(auto && elem: MyCds){ std::cout << elem.GetAuthor() << std::endl; //How can I acess the tracks of the particular cd ? } }
Standard library containers automatically keep track of their size. You don't have to do anything like that.
If you want to access only one specific element of the vector, take a look at the documentation:Another question:
I want to access the tracks of one particular cd. Can I use another for? I don't know which is the best way.
vector - C++ Reference
Do you see a function that might be suitable?
I didn't explain myself very well
I think that is interesting when a cd is appended to the colllection a number be attributed to it.
Example, when you have a collection with 2 cds, there is a CD 1 and a CD2, for instance.
To acess the tracks of a particular cd which belongs to a collection I think that I need to use the operator [] .
With size function I can get the tracks size of a particular cd, however I didn't find out how to properly create the "for-cycle".
Unless you mean to name your CDs arbitrarily, you still don't need it.
There are four ways to get a CD from a collection, two of which are interesting.
The first way you iterate over all, by which you can keep track of which CD you're currently accessing either by using indices or using a helper variable.
The second way is to get a specific CD by an index. But by knowing the index, you know what CD "number" it is.
Bear in mind that operator [] causes undefined behavior if you access an index that does not exist. For that very reason, I strongly recommend against using it unless you really need the speed. Using the .at() function helps you more easily catch bugs where you access elements that do not exist.To acess the tracks of a particular cd which belongs to a collection I think that I need to use the operator [] .
I don't know what you mean with "for-cycle."With size function I can get the tracks size of a particular cd, however I didn't find out how to properly create the "for-cycle".