Forum Replies Created

Viewing 15 posts - 196 through 210 (of 349 total)
  • Author
    Posts
  • in reply to: How does (std::cin >> x) or (std::cout << x) work #219735
    RainerRainer
    Keymaster
        Up
        0
        Down
        ::

        The while loop breaks if the std::cin is not in the std::ios::goodbit state. Here are the other state, std::cin could have. I also added a few causes for the specific states:

        • std::ios::eofbit
          • Reading beyond the last valid character.
        • std::ios::failbit
          • False formatted reading.
          • Reading beyond the last valid character.
          • Opening of a file went wrong.
        • std::ios::badbit
          • Size of the stream buffer cannot be adjusted.
          • Code conversion of the stream buffer went wrong.
          • A part of the stream threw an exception.

        In the concrete example, std::ios::failbit (false formatted reading) is the tyical cause for breaking the while loop.

        in reply to: Replacing the buffer exercise #215175
        RainerRainer
        Keymaster
            Up
            0
            Down
            ::

            First of all, my implementation of virtual overflow member function introduces an indirection:

            int_type overflow(int_type c) override {
            
                if (myStreamBuffer1->sputc(c) == traits_type::eof() || 
                    myStreamBuffer2->sputc(c) == traits_type::eof())   return traits_type::eof();
                    return c;
            }
            

            Here is the workflow. One step causes the next step in this sequence:

            1. log << “1” << ‘\n’;
            2. sputc() on log
            3. overflow() on log
            4. sputc() on the myStreamBuffer1->sputc(c) and myStreamBuffer2->sputc(c)

            Here is a pictorial description of the output buffer:

            • The output buffer is processed by three pointers
              • pbase()(put base): the beginning
              • pptr() (put pointer): the current position
              • epptr() (end put pointer): returns a position after the last character
            • When writing to the buffer with the functions sputc() or sputn() the characters are pushed to the buffer until pptr() == epptr()
            • When pptr() == epptr() holds,  the member function overflow() of the stream buffer is called, so that the characters can be written to the external device
            • Afterward, the buffer is empty again and pbase() == pptr() applies
            • If you want to explicitly synchronize (flush) the buffer with the external device, the member function sync() is called
            • If the stream buffer is degenerated, i.e. consists of only one character, each write to it simultaneously means a call to the member function overflow
            in reply to: Stream flushing #210698
            RainerRainer
            Keymaster
                Up
                0
                Down
                ::

                In general, not, because std::cout is buffered in contrast to std::cerr.

                In this particular case, yes, because any input operation on std::cin executes std::cout.flush().

                in reply to: Replacing the buffer exercise #210670
                RainerRainer
                Keymaster
                    Up
                    0
                    Down
                    ::

                    All stream objects have an associated stream buffer. teebuf is derived from std::streambuf. teebuf behaves such as a typical stream buffer with one exception: When characters are written to the associated output sequence via overflow, it puts (sputc) each character to the output sequence and advances to the next position.

                    Finally, the call std::ostream log(&myTeebuf) creates an output stream using the special stream buffer. The following constructor of std::ostream is called that takes a stream buffer as an argument: explicit ostream (streambuf* sb).

                    Additionally, I modernized the program from C++98 -> C++11 by replacing virtual with override, and the typedef declaration with the using variant.

                     

                    #include <fstream>
                    #include <iostream>
                    #include <streambuf>
                    
                    class teebuf: public std::streambuf {
                    
                    public:
                        using traits_type = std::char_traits<char>;
                        using int_type = traits_type::int_type;
                    
                        teebuf(std::streambuf* sb1, std::streambuf* sb2): myStreamBuffer1(sb1),myStreamBuffer2(sb2) {}
                    
                        // overflow will be invoked in case of output
                        // sputc sends the char c to the underlying buffer
                        int_type overflow(int_type c) override {
                    
                            if (myStreamBuffer1->sputc(c) == traits_type::eof() || 
                                myStreamBuffer2->sputc(c) == traits_type::eof())   return traits_type::eof();
                            return c;
                          }
                    private:
                        std::streambuf * myStreamBuffer1;
                        std::streambuf * myStreamBuffer2;
                    };
                    
                    int main() {
                    
                      std::cout << '\n';
                      
                      std::ofstream logfile("logfile.txt");
                      teebuf myTeebuf(std::cout.rdbuf(), logfile.rdbuf());
                    
                      std::ostream log(&myTeebuf);
                    
                      log << "1" << '\n';
                      log << "2" << '\n';
                      log << "3" << '\n';
                      
                      std::cout << '\n';
                      
                    }
                    

                     

                    in reply to: Wrong and missing videos from week 26 #165372
                    RainerRainer
                    Keymaster
                        Up
                        0
                        Down
                        ::

                        Wow. I fixed the issues.

                        Thanks a lot,

                        Rainer

                        in reply to: Wrong and missing videos from week 26 #165357
                        RainerRainer
                        Keymaster
                            Up
                            0
                            Down
                            ::

                            Thanks a lot. I fixed it.

                            in reply to: Abstract class variable members. A good idea? #151724
                            RainerRainer
                            Keymaster
                                Up
                                0
                                Down
                                ::

                                Let me quote your two questions and answer them:

                                1. It’s a common technique that a virtual member function of a derived class invokes a virtual member function of the base class with the same name. It’s a kind of a decorator. Y0u have to call the virtual function of the base call fully qualified. When not, you end with a recursion.
                                2. In general, an abstract base class should have no state. On the contrary, if the abstract base class has a static counter, this is a valid use case.

                                By the way, there is a nicer way in C++17 to initialize a static directly. Use inline:

                                class Character
                                {
                                public:
                                    Character();
                                    virtual ~Character() = 0;
                                    virtual void Attack(float applied_damage) const = 0;
                                
                                    inline static int characterCount{};  
                                };
                                

                                 

                                in reply to: Constexpr of std::string objects #147089
                                RainerRainer
                                Keymaster
                                    Up
                                    0
                                    Down
                                    ::

                                    This is undefined behavior: constexpr std::string_view myStringView{“Hello World!”}; You refer to a temporary string literal.

                                    You cannot define a constexpr std::string, but you can use a std::string in a constexpr function.

                                    #include <iostream>
                                    #include <string>
                                    
                                    constexpr int size() {
                                        std::string s("adfasdfasdf");
                                        return s.size();
                                    }
                                    int main() {
                                    
                                        std::cout <<  '\n';
                                    
                                        constexpr int len = size();
                                        std::cout << "len: " << len << '\n';  // 11
                                    
                                        std::cout << '\n';
                                    
                                    }
                                    
                                    in reply to: Function Hiding vs Overriding #142555
                                    RainerRainer
                                    Keymaster
                                        Up
                                        0
                                        Down
                                        ::

                                        First, a short remark. When you use override in a member function declaration, you should not use virtual because override implies virtual. The same rule applies to final.

                                        virtual void Print() const override
                                        {
                                            Person::Print();    //Call base class function to help
                                            std::cout << " is a student. GPA: " << gpa << '\n';
                                        }
                                        

                                        I hope I get you right. To get virtuality or late binding, you need two ingredients: an indirection such as a pointer or a reference and a virtual member function. If one of both is missing, you get early binding:

                                        Person *p1 = new Student("Emmet Brown", "Inventor", 5.0);
                                        p1->Non_Virtual_Print();   
                                        p1->Print(); 
                                        

                                        The static type of  *p1 is Person, but the dynamic type is Student.  This means that in p1->Non_Virtual_Print() the static type is used, but in p1->Print() the dynamic type.

                                        Regard hiding.

                                        struct Base {
                                            void show(double) {};
                                        };
                                        
                                        struct Derived: public Base {
                                            void show(int) {}
                                        };
                                        
                                        
                                        int main() {
                                            Derived d;
                                            d.show(5.5); // calls Derived::show
                                        }
                                        

                                        When you call d.show(5.5), the name lookup process searches for the first occurrence of the member function show. Consequentially, the lookup process is stopped when Derived is parsed. A better implementation of show in the base class Base is, therefore, not considered.

                                        in reply to: std::string_view vs std::vector question #120138
                                        RainerRainer
                                        Keymaster
                                            Up
                                            0
                                            Down
                                            ::

                                            This is a typical trap many C++ user fall into. Me included.

                                            You can assign an int to a double, but not a std::vector<int> to a std::vector<double>.

                                            #include <vector>
                                            
                                            int main() {
                                                int i = 5;
                                                double d = 5.5;
                                                d= i;
                                            
                                                std::vector<int> myIntVec{1, 2, 3};
                                                std::vector<double> myDoubleVec{1.1, 2.2, 3.3};
                                                myDoubleVec = myIntVec; // ERROR
                                            
                                            }
                                            

                                            In the concrete case, the copy assignment operator on std::vector is called. The types must match exactly match and an int is not a double, and a std::string is not a std::string.

                                            To make this work, a std::vector needs a generic copy assignment operator. I explained this in the following example: https://www.modernescpp.org/topics/example-templateclasstemplatememberfunctions-cpp/.

                                            in reply to: Function reprotoypting in different scopes. #120133
                                            RainerRainer
                                            Keymaster
                                                Up
                                                0
                                                Down
                                                ::

                                                Here are the essential C++ rules for default arguments of functions:

                                                1. At the point of a function call, the defaults are a union of the defaults provided in all visible declarations for the function.
                                                2. A redeclaration cannot introduce a default for an argument for which a default is already visible (even if the value is the same).
                                                #include <iostream>
                                                
                                                using std::string;
                                                
                                                // Function prototype
                                                void concat(const string& x, const string& y, const string& z);
                                                
                                                void func(const std::string& x, const std::string& y, const std::string& z) {
                                                    // Local prototype with default value
                                                    void concat(const string& x, const string& y, const string& z = "c");
                                                    concat("a", "b", "c");
                                                    concat("a", "b");
                                                    // void concat(const std::string& x, const std::string& y, const std::string& z = "c");       // Error (2)
                                                    // void concat(const std::string& x, const std::string& y, const std::string& z = "d");       // Error (2)
                                                    // void concat(const std::string& x, const std::string& y = "b", const std::string& z = "d"); // Error (2)
                                                    void concat(const std::string& x, const std::string& y = "b", const std::string& z);          // a default for y
                                                    concat("a", "c"); // (1)
                                                    concat("a");      // (1)
                                                }
                                                
                                                // Function definition
                                                void concat(const string& x, const string& y, const string& z){ 
                                                    std::cout << x + y + z << '\n';
                                                }
                                                
                                                
                                                int main() {
                                                    func("a", "b", "c");
                                                }
                                                

                                                You can study the program on the Compiler Explorer.

                                                in reply to: Wrong video for the lesson “string.cpp” #115106
                                                RainerRainer
                                                Keymaster
                                                    Up
                                                    0
                                                    Down
                                                    ::

                                                    Thanks a lot. Fixed.

                                                    in reply to: Missing Week 25 Intro Video #115096
                                                    RainerRainer
                                                    Keymaster
                                                        Up
                                                        0
                                                        Down
                                                        ::

                                                        This is intentional. Week 25 will start tomorrow. On Saturday, I usually record my introduction video.

                                                        in reply to: Wrong video for the lesson “string.cpp” #114256
                                                        RainerRainer
                                                        Keymaster
                                                            Up
                                                            0
                                                            Down
                                                            ::

                                                            Thanks a lot. Fixed.

                                                            in reply to: Calling a non const function of a const object #113227
                                                            RainerRainer
                                                            Keymaster
                                                                Up
                                                                0
                                                                Down
                                                                ::

                                                                Casting away const from a const created object and try to modify it is undefined behavior: https://godbolt.org/z/YMn9jbdc7.

                                                                #include <iostream>
                                                                
                                                                int main() { 
                                                                
                                                                    int nonConstInt = 10;
                                                                    int* pToNonConstInt = &nonConstInt;
                                                                    *pToNonConstInt = 12; 
                                                                    std::cout << nonConstInt << '\n';
                                                                
                                                                
                                                                    const int constInt = 10;
                                                                    const int* pToConstInt = &constInt;
                                                                    int* pToInt = const_cast<int*>(pToConstInt);
                                                                    *pToInt = 12; // undefined behavior
                                                                    std::cout << constInt << '\n';
                                                                
                                                                } 
                                                                

                                                                The modification of pToInt has no effect.

                                                                I suggest the following. Make all non-const member functions const. Duplicate the member functions that must also be non-const, and let the non-const version invoke the const versions. Therefore, you avoid code duplication and undefined behavior.

                                                                The first version of this idea is based on C++98, the second version on C++17:

                                                                • C++98

                                                                #include <iostream>
                                                                
                                                                struct C {
                                                                  const int& get() const {
                                                                    return c;
                                                                  }
                                                                  int& get() {
                                                                    return const_cast<int &>(static_cast<const C &>(*this).get());
                                                                  }
                                                                  int c{5};
                                                                };
                                                                
                                                                int main() { 
                                                                
                                                                    C c;
                                                                    const C c2;
                                                                
                                                                    c.get();
                                                                    c2.get();
                                                                
                                                                } 
                                                                
                                                                • C++17:

                                                                #include <iostream>
                                                                #include <utility>
                                                                
                                                                struct C {
                                                                  const int& get() const {
                                                                    return c;
                                                                  }
                                                                  int& get() {
                                                                    return const_cast<int&>(std::as_const(*this).get());
                                                                  }
                                                                  int c{5};
                                                                };
                                                                
                                                                int main() { 
                                                                
                                                                    C c;
                                                                    const C c2;
                                                                
                                                                    c.get();
                                                                    c2.get();
                                                                
                                                                } 
                                                                
                                                              Viewing 15 posts - 196 through 210 (of 349 total)