Thread: Learning C++ by Example

  1. #16
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    >>vector<AudioTrack> newTracks;
    >>MusicCD cd(newTracks);
    >>cd.addNewTracks(newTracks);
    The idea is that you create your tracks, then add it:

    vector<AudioTrack> NewTracks;
    NewTracks.emplace_back("My Title", 1/*minutes*/, 1/*seconds*/);
    MusicCD cd(NewTracks);
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #17
    Registered User
    Join Date
    Nov 2010
    Posts
    122
    Quote Originally Posted by Elysia View Post
    >>vector<AudioTrack> newTracks;
    >>MusicCD cd(newTracks);
    >>cd.addNewTracks(newTracks);
    The idea is that you create your tracks, then add it:

    vector<AudioTrack> NewTracks;
    NewTracks.emplace_back("My Title", 1/*minutes*/, 1/*seconds*/);
    MusicCD cd(NewTracks);
    I add
    NewTracks.emplace_back(1, "My Title", 1/*minutes*/, 1/*seconds*/);

    Because I have 4 args.
    I had an error, I forgot creating the musicCD destructor, So I had an error.

    I think that is working, should I create a print function to verify?

    Thanks!

  3. #18
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You don't need to add destructors. They are added implicitly by the compiler if you don't have one. So the rule of thumb is that if you need to do some cleanup, add one; otherwise, don't. You currently don't need any cleanup, so you don't need destructors.
    You should do create a debug print function, use a debugger to verify or implement a way to get all audio tracks so you can verify that it is right (typically done via an iterator interface).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #19
    Registered User
    Join Date
    Nov 2010
    Posts
    122
    I've done another update.
    I've got several doubts. I'll try post it clear.

    Firstly, I think that I did right what you've suggestted.
    I created a sucessful print function at musicd class which test what are being used at main. Is it an interface? it solves my "problem".

    Code:
    void MusicCD::printTrackVector(std::vector<AudioTrack> & myTracks){
    
        unsigned int size = myTracks.size();
        for (unsigned int i=0; i < size; i++){
            std::cout << "Track Number: " << myTracks[i].trackNumber() << std::endl;
            std::cout << "Track Title: " << myTracks[i].trackTitle() << std::endl;
            std::cout << "Track has  " << myTracks[i].minutes()
                      << " minutes " << myTracks[i].seconds() << " seconds " << std::endl;
        }
    
    }

    I create an album class. This is the Constructor:
    Code:
    Album(int barCode, std::string const &title, std::string const &author,
              std::string const &publisher, int year,
              float price, std::vector <MusicCD> myCds);
    Album is a derived class from Product. Do I need to put all the attributes that is inheriting from Product?
    At Album Class I created a function to add Cds. Is there that I should use the "code test" to add vectors of tracks?
    Code:
    void Album::addNewCd(std::vector<MusicCD> & myCds){
    
        int noCds;
    
        std::cout << "how many Cds has this album ? " << "\n";
        std::cin >> noCds;
    
        for (int i=0; i<= noCds; i++){
    
            std::cout << "Insert the data of CD no " << i << "\n";
    
            //Should I use here the code at main?
            //Should I create here the Track objects?
    
    
        }
    
    }

    At last. Album and gameCd classes need override the setPrice mutator functions from Product. I think this is a "kind of polymorphism". Do I need to create a virtual class?


    Thanks, I'm evolving

    Updated git:
    https://github.com/CreativeSoftware/...kStoreExample/

  5. #20
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by marcoesteves View Post
    Firstly, I think that I did right what you've suggestted.
    I created a sucessful print function at musicd class which test what are being used at main. Is it an interface? it solves my "problem".
    Take a step back. What is this "debug" function supposed to do? What information does it need? Where does this information come from?

    Album is a derived class from Product. Do I need to put all the attributes that is inheriting from Product?
    That depends on your design. If you put all the attributes in the constructor, you are forcing the user to fill in all that. That is, in your design, the user is responsible for setting appropriate barcodes, etc.
    But it is possible to delegate this responsibility to someone else, e.g. your store. Think about who you want to be responsible. Think of a real world scenario you want to emulate and this think of the different involved parties and how they're related.

    At Album Class I created a function to add Cds. Is there that I should use the "code test" to add vectors of tracks?
    Again, take a step back. What is the function supposed to do? What information does it need? Where does it get that information?

    At last. Album and gameCd classes need override the setPrice mutator functions from Product. I think this is a "kind of polymorphism". Do I need to create a virtual class?
    You are using polymorphism since you are deriving from base classes with a similar interface. Why do you think you need a virtual class?
    Think: what happens if the user calls SetPrice on a GameCD or an Album? According to the spec, their price is fixed.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #21
    Registered User
    Join Date
    Nov 2010
    Posts
    122
    Quote Originally Posted by Elysia View Post
    Take a step back. What is this "debug" function supposed to do? What information does it need? Where does this information come from?
    I got your point. And I don't know how to answer. As a procedural programmer, I always use prints as debug. I think is time to learn how to properly use debug functions, I don't know how.

    Quote Originally Posted by Elysia View Post
    Again, take a step back. What is the function supposed to do? What information does it need? Where does it get that information?
    I'll answer after solving the 1st point

    Quote Originally Posted by Elysia View Post
    You are using polymorphism since you are deriving from base classes with a similar interface. Why do you think you need a virtual class?
    Think: what happens if the user calls SetPrice on a GameCD or an Album? According to the spec, their price is fixed.
    Usually in litterature I found Polymorphins= virtual classes. Probably this is a mistake.
    If a user calls a setprice on a GameCD it will broke my program.
    I can initialize the price value in the Constructors, without overriding mutator functions. I'd like to know which is the best approach.

  7. #22
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by marcoesteves
    I got your point. And I don't know how to answer. As a procedural programmer, I always use prints as debug. I think is time to learn how to properly use debug functions, I don't know how.
    Err... they are the same thing. You are basically printing something as a log for debugging. One could do this with say, fprintf to stderr in a C program, or write to std::cerr in a C++ program, or have an elaborate logging framework to write to a file specified by some configuration file somewhere, or send an email to someone somewhere, but it is essentially the same idea.

    Such logging does have its place, but during development another tool is available to you: the debugger. You might or might not have used it "as a procedural programmer", but generally as a programmer it is a tool to consider.

    Quote Originally Posted by marcoesteves
    Usually in litterature I found Polymorphins= virtual classes. Probably this is a mistake.
    More likely this is a misunderstanding on your part. One way to accomplish polymorphism in C++ is to declare a virtual member function in a base class, then override it in a derived class. This technique requires the use of class based inheritance, but usually the inheritance itself does not have to be virtual (which is what people usually mean by "virtual classes").
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #23
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by marcoesteves View Post
    I got your point. And I don't know how to answer. As a procedural programmer, I always use prints as debug. I think is time to learn how to properly use debug functions, I don't know how.
    You are overthinking it. Using prints to debug is fine. But I want you to consider the scope of the function - what information is it supposed to print, and where does it get the information from?
    Consider these examples:

    Code:
    void debug(const int& mycolor_value) { std::cout << "debug: " << mycolor_value << "\n"; }
    
    class color
    {
    public:
        void debug(const int& mycolor_value) { std::cout << "debug: " << mycolor_value << "\n"; }
        void debug() { std::cout << "debug: " << m_mycolor_value << "\n"; }
    private:
        int m_mycolor_value;
    };
    What does these functions do? Yes, they print a variable - but if we think in higher terms, what do they do? What information do they print? Where does it get that information from and what significance does it have? Some functions take an argument and some use member variables. But how does it differ? What sense does it make to take arguments versus using member variables?

    If you are to do object-oriented programming, you must first understand object state and what it is good for.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #24
    Registered User
    Join Date
    Nov 2010
    Posts
    122
    Quote Originally Posted by laserlight View Post
    Such logging does have its place, but during development another tool is available to you: the debugger. You might or might not have used it "as a procedural programmer", but generally as a programmer it is a tool to consider.
    The self-learner problem is these type of things. When someone doesn't guide you, you won't learn. I've only used debugger when I programmed microcontrollers.

    Quote Originally Posted by laserlight View Post
    More likely this is a misunderstanding on your part. One way to accomplish polymorphism in C++ is to declare a virtual member function in a base class, then override it in a derived class. This technique requires the use of class based inheritance, but usually the inheritance itself does not have to be virtual (which is what people usually mean by "virtual classes").
    Yes, it is possible that is a misunderestood. I'll read again.

  10. #25
    Registered User
    Join Date
    Nov 2010
    Posts
    122
    Quote Originally Posted by Elysia View Post

    Code:
    void debug(const int& mycolor_value) { std::cout << "debug: " << mycolor_value << "\n"; }
    
    class color
    {
    public:
        void debug(const int& mycolor_value) { std::cout << "debug: " << mycolor_value << "\n"; }
        void debug() { std::cout << "debug: " << m_mycolor_value << "\n"; }
    private:
        int m_mycolor_value;
    };
    I want to learn OOP, so, I'll try to understad.
    Assuming there are a main function which calls the "debugs".
    I think the 1st one, after the class declaration, it will be called as debug(const int& mycolor_value) and it will print the value of mycolor_value, as an acessor function.
    The 2nd one will be called as colorObject.debug(const int& mycolor_value). This one will print mycolor_value like an acessor function.
    The 3rd I'm not so sure. I think that will print nothing since m_mycolor_value is a private variable.

  11. #26
    Registered User
    Join Date
    Nov 2010
    Posts
    122
    About the Album Class functionalaties.

    The album class is suppossed to "know" how many cds the particular album will have.
    Then must be created n - MusicCDs Class objects, which one will have a vector of audiotracks.

    I'm thinking how can I implement on an efficient way.

  12. #27
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by marcoesteves View Post
    I want to learn OOP, so, I'll try to understad.
    Assuming there are a main function which calls the "debugs".
    I think the 1st one, after the class declaration, it will be called as debug(const int& mycolor_value) and it will print the value of mycolor_value, as an acessor function.
    The 2nd one will be called as colorObject.debug(const int& mycolor_value). This one will print mycolor_value like an acessor function.
    The 3rd I'm not so sure. I think that will print nothing since m_mycolor_value is a private variable.
    You need to think about what functions are good where, how objects help and why. Classes are great when you need to group dependent data and perform actions upon those.
    In my example, all three functions do the same thing, but their interface differs. Since we have a color class, which of the function are more appropriate, especially considering that m_mycolor_value is private (i.e. the users of the class cannot access it)?
    Your answer for the 3rd is completely incorrect, making me believe you do not understand encapsulation and access modifiers yet. You should probably brush up on this.

    Now let's take an example. The Music CD class.
    We have something abstract: an idea, perhaps something concrete that can be touched, felt. We need to make a decision on how to model this.

    So first of, what do a music cd consist of?
    It has an author, (total) length and tracks (and perhaps more).

    So what can we do with a music cd (i.e. operations)?
    At this point, we can imagine setting and getting all of its properties (e.g. set/get author, length and tracks).

    Now, how can we model this?
    We could have an array of authors, lengths and an array of arrays of tracks, but this spreads highly correlated data around, so we should probably group them. E.g.:
    Not:
    Code:
    std::array<std::string, N> Author;
    std::array<int, N> Length;
    std::array<std::vector<XTrackInfo>, N> TrackInfo;
    Instead:
    Code:
    struct XMusicCd
    {
        std::string Author;
        int Length;
        std::vector<XTrackInfo> TrackInfo;
    };
    
    std::array<XMusicCd, N> MusicCd;
    This groups correlated data together. Now let's define operations. Since they're just getters and setters, we really don't have to do anything at all, but let's just do that for the example's sake. So we would have:

    void SetAuthor(XMusicCd& Cd, std::string Author);
    const std::string& GetAuthor(XMusicCd& Cd);
    // ...

    So what do these operation functions need? That is, what information must they take, and where do they get that information? Well, we said that they operated on CDs, so obviously you must tell them what CD they should operate on. Hence, the first argument is the CD. For set, the function must know the new author to set. This information must come from the user since the user wants to set a new user. Hence, the set function takes another argument.

    But note that both functions take a reference to the CD. This implies that they are operations for CDs and are highly correlated to the CD data (i.e. they need access to the CD data). So we could group these operations together with the data:


    Code:
    class XMusicCd
    {
    private:
        std::string m_Author;
        int m_Length;
        std::vector<XTrackInfo> m_TrackInfo;
    
    public:
        void SetAuthor(std::string Author);
        const std::string& GetAuthor() const;
    };
    
    std::array<XMusicCd, N> MusicCd;
    Now the the CD they operate on is *this, so we don't need the user to tell us which CD to operate on by passing another argument. This is implicit since the user invokes the function on the object (i.e. CD) to operate on.

    Now, the set author wants to set the author of the CD, and it has access to the CD to set the author on. So where is the information it should modify? It should be obvious that it is (*this).Author. After all, set author implies that we should set the Author member on the object the function was invoked on.

    How about GetAuthor then? GetAuthor must know from which object to get the author from. Following the same logic, we know what object it operates on, i.e. *this. So the implementations of these functions would be:

    Code:
        void SetAuthor(std::string Author) { m_Author = Author; }
        const std::string& GetAuthor() const { return m_Author; }
    Now I ask you: which of the following functions would be appropriate for Length and how would you implement them?
    Code:
    void SetLength(XMusicCd& Cd, int Length);
    void XMusicCd::SetLength(XMusicCd& Cd, int Length);
    void XMusicCd::SetLength(int Length);
    
    int GetLength(XMusicCd& Cd);
    int XMusicCd::GetLength(XMusicCd& Cd) const;
    int XMusicCd::GetLength() const;
    Note that this is just a basic modelling example. In the real world, you have to consider other things, such as how much code duplication, maintainability, difficulty of implementation, etc. But this is a good starting point.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #28
    Registered User
    Join Date
    Nov 2010
    Posts
    122
    I need to read very carefully more than 1 time.
    Thank you, I think that you were clear, I need to figure out a couple of things.

  14. #29
    Registered User
    Join Date
    Nov 2010
    Posts
    122
    Quote Originally Posted by Elysia View Post
    Your answer for the 3rd is completely incorrect, making me believe you do not understand encapsulation and access modifiers yet. You should probably brush up on this.
    The 3rd debug() prints the value of the private variable.

    Quote Originally Posted by Elysia View Post
    Instead:
    Code:
    struct XMusicCd
    {
        std::string Author;
        int Length;
        std::vector<XTrackInfo> TrackInfo;
    };
    
    std::array<XMusicCd, N> MusicCd;
    Just a note. In my example, I'm always using the std::vector. Should I switch to the array? I read the c++ reference and I think it is more correct use std::array when you know the vector size. So, when a user choose the number of tracks or the number of cds on an album, the size won't change, correct?

    Quote Originally Posted by Elysia View Post
    Now I ask you: which of the following functions would be appropriate for Length and how would you implement them?
    Code:
    void SetLength(XMusicCd& Cd, int Length);
    void XMusicCd::SetLength(XMusicCd& Cd, int Length);
    void XMusicCd::SetLength(int Length);
    
    int GetLength(XMusicCd& Cd);
    int XMusicCd::GetLength(XMusicCd& Cd) const;
    int XMusicCd::GetLength() const;
    This is not clear to me.
    The total length variable must be calculated, correct?
    But the total length isn't a sum of the lengths of all tracks of TrackInfo vector?

  15. #30
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by marcoesteves View Post
    The 3rd debug() prints the value of the private variable.
    It does.

    Just a note. In my example, I'm always using the std::vector. Should I switch to the array? I read the c++ reference and I think it is more correct use std::array when you know the vector size. So, when a user choose the number of tracks or the number of cds on an album, the size won't change, correct?
    std::array = Fixed array. Size is decided at a compile time. Cannot change at runtime.
    std::vector = Dynamic array. Size is decided at runtime. Size can change at runtime.
    So use std::array when you know the size will not change.
    Use std::vector when the size can change at runtime (i.e. depending on how many CDs there will be in any given album).

    This is not clear to me.
    The total length variable must be calculated, correct?
    But the total length isn't a sum of the lengths of all tracks of TrackInfo vector?
    You are right, but seeing as this is just an example, pay that detail no mind. Just assume that it cannot be calculated.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Learning C++
    By sLIVER in forum C++ Programming
    Replies: 2
    Last Post: 07-11-2007, 08:18 PM
  2. Learning
    By nojoegohome in forum C++ Programming
    Replies: 6
    Last Post: 07-06-2006, 04:33 AM
  3. Learning Dos and learning Windows
    By blankstare77 in forum C++ Programming
    Replies: 8
    Last Post: 07-31-2005, 03:48 PM
  4. Learning?
    By bob20 in forum A Brief History of Cprogramming.com
    Replies: 41
    Last Post: 12-11-2002, 10:17 AM

Tags for this Thread