Forum Replies Created

Viewing 15 posts - 151 through 165 (of 349 total)
  • Author
    Posts
  • in reply to: Pointer to object to decorate #550404
    RainerRainer
    Keymaster
        Up
        1
        Down
        ::

        Very good point. The first example decorator.cpp is from Wikipedia.

        Here is a value based implementation:

        #include <iostream>
        #include <memory>
        #include <string>
        
        
        struct Shape {
          virtual ~Shape() = default;
          virtual std::string GetName() const = 0;
        };
        
        struct Circle : Shape {
          std::string GetName() const override {
            return std::string("A circle of radius ") + std::to_string(radius);
          }
        
          float radius = 10.0f;
        };
        
        struct ColoredShape : Shape {
          ColoredShape(const std::string& color, std::unique_ptr<Shape> shape)
              : color(color), shape(std::move(shape)) {}
        
          std::string GetName() const override {
            return shape->GetName() + " which is colored " + color + ".";
          }
        
          std::string color;
          std::unique_ptr<Shape> shape;
        };
        
        int main() {
        
          std::cout << '\n';
        
          auto circle = std::make_unique<Circle>();
          std::cout << circle->GetName() << '\n';
          ColoredShape colored_shape("red", std::move(circle));
          std::cout << colored_shape.GetName() << '\n';
        
          std::cout << '\n';
        
        }
        

        I essentially replaced the pointer Shape* with a std::unique_ptr<Shape>.

        in reply to: Design idea for exchanging used libraries #549966
        RainerRainer
        Keymaster
            Up
            0
            Down
            ::

            Without knowing more context, I have several ideas in mind. First, the “Fundamental theorem of software engineering” come into my mind: “We can solve any problem by introducing an extra level of indirection.”

            First, I think the Adapter Pattern with Multiple Inheritance is a bad choice. The purpose of the Adapter Pattern is to adapt an interface, and you have to make your decision at compile time. Your concern is to support a generic interface with different implementations. I have two ideas.

            • Use the Strategy Pattern. Your JSON class has a pointer to a concrete JSON implementation. This concrete JSON implementation is the strategy that has to implement a JSON interface. Your existing INHOUSE::JSON implementation implements this interface, and also the new JSON implementations implement this interface. Now, you can instantiate your JSON class with a concrete JSON implementation. The classes InhouseJson and BoostJson are probably also adapter, based on the delegation.

            class JsonImplementation {
                 virtual JsonData read() = 0;
                 virtual write(JsonData data) = 0;
            };
            
            class InhouseJson: public JsonImplementation {  
               ...
            }
            
            class BoostJson: public JsonImplementation {
               ...
            }
            
            
            class JSON {
              public:
                 JSON(JSONimplementation j): json(std::make_unique<JSONImlementation>(j)) {}
                // JSON API
              private:
                std::unique_ptr<JSONimplementation> json;
            };
            
            • If the required API of the JSON class is simple, you should also consider a Facade. This means your Facade describe the simple interface that use under-the-hood the concrete JSON implementation. This has the benefit that you easily can replace the implementation because your customer use the facade.  I’m a big fan of the facade for restructuring interface. Assume, your customer should use a different implementation of a JSON library. You can do the following.
              • Define a new interface (facade) for your JSON functionality.
              • Say to your customer that he should use the new interface.
              • Replace the implementation because the customer only depend on the interface.
            in reply to: Pointer to object to decorate #548782
            RainerRainer
            Keymaster
                Up
                0
                Down
                ::

                If possible, you should use value semantics and not reference semantics. A std::shared_ptr models reference semantics. A std::shared_ptr is better than a pointer, but it models shared ownership. Reference semantics makes your code pretty complicated to reason about. For example, using a std::shared_ptr<Shape> in a concurrent environment is probably a data race. At least, you have to think about critical sections.

                A std::unique_ptr on the contrary, models value semantics.

                in reply to: Ref to implementation in implementor.cpp #548781
                RainerRainer
                Keymaster
                    Up
                    0
                    Down
                    ::

                    The crucial idea of the Bridge Pattern is that you can exchange the interface and the implementation during run time using dependency injection. For example, each client call should trigger a log message. Thanks to the Bridget Pattern, you can derive a LoggerAbstraction and a LoggerImplementation for the corresponding interface and plug it together.

                    auto loggerImplemenation = new LoggerImplementation();
                    
                    auto loggerAbstraction = new LoggerAbstraction(loggerImplementation);
                    
                    loggerAbstraction.func() // log message from the abstraction and the implementation
                    
                    auto nativeImplementation = new NativeImplementation();
                    
                    loggerAbstraction.changeImplementation(nativeImplementation);
                    
                    loggerAbstraction.func(); // Log message only form the abstraction
                    

                    The simplified Bridget Pattern pimpl does not give you this flexibility.

                    in reply to: Inheritance of Template Base class #548072
                    RainerRainer
                    Keymaster
                        Up
                        1
                        Down
                        ::

                        This is the more advanced topic of template inheritance. I used http://hilite.me/ to lay out your code. Read my post here: Surprise Included: Inheritance and Member Functions of Templates.

                        in reply to: Forum titles for Design patterns #548065
                        RainerRainer
                        Keymaster
                            Up
                            0
                            Down
                            ::

                            Sure. I fixed it.

                            in reply to: Initializer list in adapterObject.cpp #548064
                            RainerRainer
                            Keymaster
                                Up
                                1
                                Down
                                ::

                                It’s only a matter of taste. When you compile both versions with and without optimization, you see the identical assembler code. This holds also true, if I remove the move constructor.

                                in reply to: Member functions of Singleton class #547801
                                RainerRainer
                                Keymaster
                                    Up
                                    0
                                    Down
                                    ::

                                    Imagine, your singleton has a pointer to a database. For unit testing, you want to change the database with a mocked database.

                                    #include <iostream>
                                    #include <memory>
                                    
                                    struct DataBase{
                                        virtual ~DataBase() = default;
                                    };
                                    
                                    struct MockDataBase: DataBase{};
                                    
                                    class MySingleton{
                                    
                                      private:
                                        MySingleton(): myDataBase(std::make_unique<DataBase>()){}
                                        ~MySingleton()= default;
                                        std::unique_ptr<DataBase> myDataBase;
                                    
                                      public:
                                        MySingleton(const MySingleton&)= delete;
                                        MySingleton& operator=(const MySingleton&)= delete;
                                    
                                        static MySingleton& getInstance(){
                                            static MySingleton sing;
                                            return sing;
                                        }
                                    
                                        void changeDataBase(DataBase* newDataBase){
                                            myDataBase.reset(newDataBase);
                                        }
                                    
                                    };
                                    
                                    
                                    int main(){
                                    
                                      std::cout << '\n';
                                      
                                      MockDataBase mockDataBase;
                                      MySingleton::getInstance().changeDataBase(&mockDataBase);
                                      
                                    
                                      std::cout << '\n';
                                    
                                    }
                                    

                                    This is not possible with a static member function. To change the member myDataBase, you need a member function.

                                    in reply to: Factory method examples create twice? #546168
                                    RainerRainer
                                    Keymaster
                                        Up
                                        0
                                        Down
                                        ::

                                        Now, I see your point. The member function getType of Window in the program FactoryMethodClassic.cpp was only a stylistic choice. I used it just instead of an enum as an argument for the factory function getNewWindow. This would be more typical. Additionally, this implementation is pretty similar to the Prototype Pattern used in the example factoryMethodUniquePtr.cpp, and simulates virtual behavior.

                                        in reply to: Factory method examples create twice? #546044
                                        RainerRainer
                                        Keymaster
                                            Up
                                            0
                                            Down
                                            ::

                                            There is a big difference.

                                            Compare the following function signatures:

                                            std::unique_ptr<Widget> createWidget1(WindowType win);
                                            
                                            std::unique_ptr<Widget> createWidget2(std::unique_ptr<Widget>& wid);
                                            
                                            • The caller of the factory function createWidget1 has to explicitly specific the Widget he wants to have: auto createWidget(Widget::FancyWidget);
                                            • The caller of the factory function createWidget2 only want to have the same Widget. Which Widget is created depends on the concrete argument. Inside the function, you call a virtual member function such as clone or create on the Widget. Consequentially, your creation process depends not on an explicit value such as an enum, but on virtuality.

                                            std::unique_ptr<FancyWidget> fancyWidget;
                                            std::unique_ptr<DefaultWidget> defaultWidget;
                                            
                                            createWidget2(fancyWidget);
                                            createWidget2(defaultWidget);
                                            
                                            in reply to: Factory method as static member of base class #546041
                                            RainerRainer
                                            Keymaster
                                                Up
                                                0
                                                Down
                                                ::

                                                Exactly. The main concern of this example is it to call render on the dialog (dialog.render()). To perform this job, it uses a factory method to create the appropriate button (Button okButton = createButton()) .

                                                in reply to: Alternatives to Factory Method #546040
                                                RainerRainer
                                                Keymaster
                                                    Up
                                                    0
                                                    Down
                                                    ::

                                                    I discussed various ways to conditional execute code in these two posts:

                                                    From the performance point of view, CRTP is the most promising. Static polymorphism based on CRTP will be our topic in week 10.

                                                    in reply to: Factory method as static member of base class #545711
                                                    RainerRainer
                                                    Keymaster
                                                        Up
                                                        0
                                                        Down
                                                        ::

                                                        Classically, you make it inside a class. This is the reason it’s called factory method, not factory function. Furthermore, this factory method gets an object (see factoryMethodUniquePtr.cpp) like in my example or a number (see here) to decide which object should be created.

                                                        In the simple use-case, I prefer a free function; in the more advanced, a member function. A function has as serious limitation. It cannot have state. For example, when your factory method returns a std::shared_ptr and want to keep track of the created products, you need an object.

                                                        in reply to: Modeling ownership or borrowing #545710
                                                        RainerRainer
                                                        Keymaster
                                                            Up
                                                            1
                                                            Down
                                                            ::

                                                            Exactly. Imagine you create some data, used by various threads, which should automatically be destroyed when no thread needs it anymore. This use-case can nicely be modelled by a factory function returning a std::shared_ptr.

                                                            in reply to: Return preserves const? #544674
                                                            RainerRainer
                                                            Keymaster
                                                                Up
                                                                0
                                                                Down
                                                                ::

                                                                Clang will not compile this program because val has static storage duration but not automatic storage duration. Static storage duration means that it is initialized prior to program startup. Here is more information about storage duration.

                                                                Because of the storage duration, the lambda can directly access val:

                                                                #include <functional>
                                                                #include <iostream>
                                                                #include <string>
                                                                
                                                                const std::string val = "on stack created"; 
                                                                
                                                                std::function<std::string()> makeLambda() {
                                                                  return []{return val;};
                                                                }
                                                                
                                                                int main(){
                                                                
                                                                  auto bad = makeLambda();
                                                                  std::cout << bad();
                                                                
                                                                }
                                                                
                                                              Viewing 15 posts - 151 through 165 (of 349 total)