DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Curious about the future of data-driven systems? Join our Data Engineering roundtable and learn how to build scalable data platforms.

Data Engineering: The industry has come a long way from organizing unstructured data to adopting today's modern data pipelines. See how.

Threat Detection: Learn core practices for managing security risks and vulnerabilities in your organization — don't regret those threats!

Managing API integrations: Assess your use case and needs — plus learn patterns for the design, build, and maintenance of your integrations.

Avatar

Vishal Chovatiya

Senior Member Of Technical Staff at CircuitSutra

BENGALURU, IN

Joined Apr 2020

http://www.vishalchovatiya.com/

About

Software Developer⌨, Fitness Freak, Geek, Hipster, Blogger, Productivity Hacker⌚, Always a Student & Learning Junkie. Msg here ===>>> http://www.vishalchovatiya.com/contact-2/

Stats

Reputation: 752
Pageviews: 421.2K
Articles: 21
Comments: 2
  • Articles
  • Comments

Articles

article thumbnail
Facade Design Pattern in Modern C++
To provide unified interface by hiding system complexities.
October 5, 2020
· 11,383 Views · 3 Likes
article thumbnail
Decorator Design Pattern in Modern C++
To facilitates the additional functionality to objects.
September 17, 2020
· 15,461 Views · 2 Likes
article thumbnail
Composite Design Pattern in Modern C++
To treat individual & group of objects in a uniform manner.
September 8, 2020
· 11,568 Views · 2 Likes
article thumbnail
Adapter Design Pattern in Modern C++
In software engineering, Structural Design Patterns deal with the relationship between object and classes i.e. how objects and classes interact or build a relationship in a manner suitable to the situation. The structural design patterns simplify the structure by identifying relationships. In this article of the Structural Design Patterns, we're going to take a look at Adapter Design Pattern in Modern C++ which used to convert the interface of an existing class into another interface that client/API-user expect. Adapter Design Pattern makes classes work together that could not otherwise because of incompatible interfaces. By the way, If you haven't check out my other articles on Structural Design Patterns, then here is the list: Adapter Bridge Composite Decorator Facade Flyweight Proxy The code snippets you see throughout this series of articles are simplified not sophisticated. So you often see me not using keywords like override, final, public(while inheritance) just to make code compact & consumable(most of the time) in single standard screen size. I also prefer struct instead of class just to save line by not writing "public:" sometimes and also miss virtual destructor, constructor, copy constructor, prefix std::, deleting dynamic memory, intentionally. I also consider myself a pragmatic person who wants to convey an idea in the simplest way possible rather than the standard way or using Jargons. Note: If you stumbled here directly, then I would suggest you go through What is design pattern? first, even if it is trivial. I believe it will encourage you to explore more on this topic. All of this code you encounter in this series of articles are compiled using C++20(though I have used Modern C++ features up to C++17 in most cases). So if you don't have access to the latest compiler you can use https://wandbox.org/ which has preinstalled boost library as well. Intent To get the interface you want from the interface you have. An adapter allows two incompatible classes to work together by converting the interface of one class into an interface expected by the client/API-user without changing them. Basically, adding intermediate class i.e. Adapter. If you find yourself in a situation of using Adapter then you might be working on compatibility between libraries, modules, plugins, etc. If not then you might have serious design issues because, if you have followed Dependency Inversion Principle early in the design. Use of Adapter Design Pattern won't be the case. Adapter Design Pattern Examples in C++ Implementing an Adapter Design Pattern is easy, just determine the API you have & the API you need. Create a component which aggregates(has a reference to,...) the adaptee. Classical Adapter C++ x 32 1 struct Point { 2 int32_t m_x; 3 virtual void draw(){ cout<<"Point\n"; } 4 }; 5 6 struct Point2D : Point { 7 int32_t m_y; 8 void draw(){ cout<<"Point2D\n"; } 9 }; 10 11 void draw_point(Point &p) { 12 p.draw(); 13 } 14 15 struct Line { 16 Point2D m_start; 17 Point2D m_end; 18 void draw(){ cout<<"Line\n"; } 19 }; 20 21 struct LineAdapter : Point { 22 Line& m_line; 23 LineAdapter(Line &line) : m_line(line) {} 24 void draw(){ m_line.draw(); } 25 }; 26 27 int main() { 28 Line l; 29 LineAdapter lineAdapter(l); 30 draw_point(lineAdapter); 31 return EXIT_SUCCESS; 32 } You can also create a generic adapter by leveraging C++ template as follows: C++ xxxxxxxxxx 1 1 template 2 struct GenericLineAdapter : Point { 3 T& m_line; 4 GenericLineAdapter(T &line) : m_line(line) {} 5 void draw(){ m_line.draw(); } 6 }; The usefulness of the generic approach hopefully becomes more apparent when you consider that when you need to make other things Point-like, the non-generic approach becomes quickly very redundant. Pluggable Adapter Design Pattern using Modern C++ The Adapter should support the adaptees(which are unrelated and have different interfaces) using the same old target interface known to the client/API-user. Below example satisfy this property by using C++11's lambda function & functional header. C++ xxxxxxxxxx 1 36 1 /* Legacy code -------------------------------------------------------------- */ 2 struct Beverage { 3 virtual void getBeverage() = 0; 4 }; 5 6 struct CoffeeMaker : Beverage { 7 void Brew() { cout << "brewing coffee" << endl;} 8 void getBeverage() { Brew(); } 9 }; 10 11 void make_drink(Beverage &drink){ 12 drink.getBeverage(); // Interface already shipped & known to client 13 } 14 /* --------------------------------------------------------------------------- */ 15 16 struct JuiceMaker { // Introduced later on 17 void Squeeze() { cout << "making Juice" << endl; } 18 }; 19 20 struct Adapter : Beverage { // Making things compatible 21 function m_request; 22 23 Adapter(CoffeeMaker* cm) { m_request = [cm] ( ) { cm->Brew(); }; } 24 Adapter(JuiceMaker* jm) { m_request = [jm] ( ) { jm->Squeeze(); }; } 25 26 void getBeverage() { m_request(); } 27 }; 28 29 int main() { 30 Adapter adp1(new CoffeeMaker()); 31 make_drink(adp1); 32 33 Adapter adp2(new JuiceMaker()); 34 make_drink(adp2); 35 return EXIT_SUCCESS; 36 } The pluggable adapter sorts out which object is being plugged in at the time. Once an object has been plugged in and its methods have been assigned to the delegate objects(i.e. m_request in our case), the association lasts until another set of methods is assigned. What characterizes a pluggable adapter is that it will have constructors for each of the types that it adapts. In each of them, it does the delegate assignments (one, or more than one if there are further methods for rerouting). Pluggable adapter provides the following two main benefits: You can bind an interface(bypassing lambda function in constructor argument), unlike the object we did in the above example. This also helps when adapter & adaptee have a different number of the argument. Benefits of Adapter Design Pattern Open-Closed Principle: One advantage of the Adapter Pattern is that you don't need to change the existing class or interface. By introducing a new class, which acts as an adapter between the interface and the class, you avoid any changes to the existing code. This also limits the scope of your changes to your software component and avoids any changes and side-effects in other components or applications. By above two-point i.e. separate class(i.e. Single Responsibility Principle) for special functionality & fewer side-effects, it's obvious we do requires less maintenance, learning curve & testing. AdapterDesing Pattern also adheres to the Dependency Inversion Principle, due to which you can preserve binary compatibility between multiple releases. Summary by FAQs When to use the Adapter Design Pattern? -- Use the Adapter class when you want to use some existing class, but its interface isn't compatible with the rest of your code. -- When you want to reuse several existing subclasses that lack some common functionality that can't be added to the superclass. -- For example, let say you have a function which accepts weather object & prints temperature in Celsius. But now you need to print the temperature in Fahrenheit. In this case of an incompatible situation, you can employ the Adapter Design Pattern. Real-life & practical example of the Adapter Design Pattern? -- In STL, stack, queue & priority_queue are adaptors from deque & vector. When stack executes stack::push(), the underlying vector does vector::push_back(). -- A card reader which acts as an adapter between the memory card and a laptop. -- Your mobile & laptop charges are kind of adapter which converts standard voltage & current to the required one for your device. What are the differences between Bridge & Adapter Design Pattern? -- Adapter is commonly used with an existing app to make some otherwise-incompatible classes work together nicely. -- Bridge is usually designed up-front, letting you develop parts of an application independently of each other. What is the difference between Decorator & Adapter Design Pattern? -- Adapter converts one interface to another, without adding additional functionalities\ -- Decorator adds new functionality into an existing interface. What is the difference between Proxy & Adapter Design Pattern? -- Adapter Design Pattern translates the interface for one class into a compatible but different interface. -- Proxy provides the same but easy interface or some time act as the only wrapper.
August 25, 2020
· 13,058 Views · 5 Likes
article thumbnail
Introduction to Regular Expressions With Modern C++
In this article, take a look at an introduction to regular expressions with C++.
August 20, 2020
· 23,602 Views · 4 Likes
article thumbnail
Using std::map Wisely With Modern C++
In this article, see some reasons to use std::map with Modern C++.
August 6, 2020
· 26,402 Views · 3 Likes
article thumbnail
Applying Curiously Recurring Template Pattern in C++
There is various material effectively accessible for "How" and "What" on CRTP. So, I will address the "Where" part that CRTP Applicability.
Updated August 3, 2020
· 10,079 Views · 2 Likes
article thumbnail
Singleton Design Pattern in Modern C++
To create only one instance of a class at any point in time.
July 27, 2020
· 11,115 Views · 1 Like
article thumbnail
Prototype Design Pattern in Modern C++
Prototype Design Pattern helps in the prototyping (creating/copying cheaply) an object using separate methods or polymorphic classes.
July 21, 2020
· 10,397 Views · 1 Like
article thumbnail
Builder Design Pattern in Modern C++
separating the construction of a complex object from its representation
July 13, 2020
· 12,999 Views · 1 Like
article thumbnail
C++ Template Story So Far (C++11 to C++20)
I will start with a simple class/function template and as we move along, it will increase the complexity.
June 25, 2020
· 12,020 Views · 2 Likes
article thumbnail
Variadic Template C++: Implementing Unsophisticated Tuple
So, in this article, I will explain the variadic template in C++ with the help of an unsophisticated tuple implementation.
Updated June 19, 2020
· 11,377 Views · 3 Likes
article thumbnail
Dependency Inversion Principle in C++: SOLID as a Rock
High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.
June 15, 2020
· 4,929 Views · 1 Like
article thumbnail
Interface Segregation Principle | SOLID as a Rock
Clients should not be forced to depend on interfaces that they do not use.
June 5, 2020
· 5,415 Views · 2 Likes
article thumbnail
What Is a Design Pattern?
In this article, explore design patterns.
May 21, 2020
· 28,511 Views · 8 Likes
article thumbnail
Double Dispatch in C++
Double Dispatch in C++ is a mechanism that dispatches a function call to different concrete functions depending on the runtime types of two objects. Learn more!
May 20, 2020
· 17,647 Views · 2 Likes
article thumbnail
Open Closed Principle: SOLID as a Rock
Open-Closed Principle(OCP) is the second principle I will discuss with minimalistic examples in Modern C++ along with its benefits.
May 18, 2020
· 6,317 Views · 2 Likes
article thumbnail
All About Lambda Functions in C++ (From C++11 to C++17)
Lambda functions are quite an intuitive concept of Modern C++ introduced in C++11, so there are already tons of articles on lambda function tutorials over the internet. But still, there are some untold things (like IIFE, types of lambda, etc.) left, which nobody talks about. Therefore, here I am to not only show you lambda function in C++, but we'll also cover how it works internally and other aspects of Lambda. The title of this article is a bit misleading. Because lambda doesn't always synthesize to function pointer. It's an expression (precisely unique closure). But I have kept it that way for simplicity. So from now on, I will use lambda function and expression interchangeably. What Is a Lambda Function? A lambda function is a short snippet of code that: Isn't worth naming (unnamed, anonymous, disposable, etc. Whatever you can call it), and also will not be reused. In other words, it's just syntactic sugar. lambda function syntax is defined as: C++ xxxxxxxxxx 1 1 [ capture list ] (parameters) -> return-type 2 { 3 method definition 4 } Usually, the compiler evaluates a return type of a lambda function itself. So we don't need to specify a trailing return type explicitly i.e. -> return-type. But, in some complex cases, the compiler unable to deduce the return type and we need to specify that. Why Use a Lambda Function? C++ includes many useful generic functions, like std::for_each, which can be handy. Unfortunately, they can also be quite cumbersome to use, particularly if the functor you would like to apply is unique to the particular function. Consider the following code for an example: C++ xxxxxxxxxx 1 14 1 struct print 2 { 3 void operator()(int element) 4 { 5 cout << element << endl; 6 } 7 }; 8 9 int main(void) 10 { 11 std::vector v = {1, 2, 3, 4, 5}; 12 std::for_each(v.begin(), v.end(), print()); 13 return 0; 14 } If you use print once, in that specific place, it seems overkill to be writing a whole class just to do something trivial and one-off. However, this kind of situation inline code would be more suitable and appropriate which can be achieved by lambda function as follows: C++ xxxxxxxxxx 1 1 std::for_each(v.begin(), v.end(), [](int element) { cout << element << endl; }); How Lambda Functions Work Internally? C++ xxxxxxxxxx 1 11 1 [&i] ( ) { std::cout << i; } 2 // is equivalent to 3 struct anonymous 4 { 5 int &m_i; 6 anonymous(int &i) : m_i(i) {} 7 inline auto operator()() const 8 { 9 std::cout << i; 10 } 11 }; The compiler generates unique closure as above for each lambda function. Finally, the secret's revealed. Capture list will become a constructor argument in the closure. If you capture argument as a value, then the corresponding type data member is created within the closure. Moreover, you can declare a variable/object in the lambda function argument, which will become an argument to call the operator i.e. operator(). Benefits of Using a Lambda Function Zero cost abstraction. Yes! You read it right. Lambda doesn't cost you performance, and it's as fast as a normal function. In addition, code becomes compact, structured, and expressive. Learning Lambda Expressions Capture by Reference/Value C++ xxxxxxxxxx 1 1 int main() 2 { 3 int x = 100, y = 200; 4 auto print = [&] { // Capturing object by reference 5 std::cout << __PRETTY_FUNCTION__ << " : " << x << " , " << y << std::endl; 6 }; 7 print(); 8 return 0; 9 } Output: C++ xxxxxxxxxx 1 1 main():: : 100 , 200 In the above example, I have mentioned & in the capture list. This captures variable x and y as a reference. Similarly, = denotes captured by value, which will create data member of the same type within the closure and copy assignment will take place. Note that the parameter list is optional; you can omit the empty parentheses if you do not pass arguments to the lambda expression. Lambda Capture List The following table shows different use cases for the same: [ ] ( ) { } no captures [=] ( ) { } captures everything by copy(not recommendded) [&] ( ) { } captures everything by reference(not recommendded) [x] ( ) { } captures x by copy [&x] ( ) { } captures x by reference [&, x] ( ) { } captures x by copy, everything else by reference [=, &x] ( ) { } captures x by reference, everything else by copy Passing Lambda as a Parameter C++ xxxxxxxxxx 1 21 1 template 2 void f(Functor functor) 3 { 4 std::cout << __PRETTY_FUNCTION__ << std::endl; 5 } 6 7 /* Or alternatively you can use this 8 void f(std::function functor) 9 { 10 std::cout << __PRETTY_FUNCTION__ << std::endl; 11 } 12 */ 13 14 int g() { static int i = 0; return i++; } 15 16 int main() 17 { 18 auto lambda_func = [i = 0]() mutable { return i++; }; 19 f(lambda_func); // Pass lambda 20 f(g); // Pass function 21 } Output: C++ xxxxxxxxxx 1 1 Function Type : void f(Functor) [with Functor = main()::] 2 Function Type : void f(Functor) [with Functor = int (*)(int)] You can also pass lambda functions as an argument to other functions just like a normal function, which I have coded above. If you noticed, here I have declared a variable i in the capture list, which will become a data member. As a result, every time you call lambda_func, it will be returned and incremented. Capture Member Variable in Lambda or This Pointer C++ xxxxxxxxxx 1 17 1 class Example 2 { 3 public: 4 Example() : m_var(10) {} 5 void func() 6 { 7 [=]() { std::cout << m_var << std::endl; }(); // IIFE 8 } 9 private: 10 int m_var; 11 }; 12 13 int main() 14 { 15 Example e; 16 e.func(); 17 } this pointer can also be captured using [this], [=] or [&]. In any of these cases, class data members(including private) can be accessed as you do in a normal method. If you see the lambda expression line, I have used extra () at the end of the lambda function declaration which used to calls it right thereafter declaration. It is called IIFE (Immediately Invoked Function Expression). C++ Lambda Function Types Generic Lambda C++ xxxxxxxxxx 1 1 const auto l = [](auto a, auto b, auto c) {}; 2 // is equivalent to 3 struct anonymous 4 { 5 template 6 auto operator()(T0 a, T1 b, T2 c) const 7 { 8 } 9 }; Generic lambda introduced in C++14 captures parameters with theauto specifier. Variadic Generic Lambda C++ xxxxxxxxxx 1 15 1 void print() {} 2 template 3 void print(const First &first, Rest &&... args) 4 { 5 std::cout << first << std::endl; 6 print(args...); 7 } 8 9 int main() 10 { 11 auto variadic_generic_lambda = [](auto... param) { 12 print(param...); 13 }; 14 variadic_generic_lambda(1, "lol", 1.1); 15 } Lambda with a variable parameter pack will be useful in many scenarios like debugging, repeated operation with different data input, etc. Mutable Lambda Function Typically, a lambda's function call operator is const-by-value, which means lambda requires the mutable keyword if you are capturing anything by-value. C++ xxxxxxxxxx 1 1 []() mutable {} 2 // is equivalent to 3 struct anonymous 4 { 5 auto operator()() // call operator 6 { 7 } 8 }; We have already seen an example of this above. I hope you noticed it. Lambda as a Function Pointer C++ xxxxxxxxxx 1 1 #include 2 #include 3 int main() 4 { 5 auto funcPtr = +[] {}; 6 static_assert(std::is_same::value); 7 } You can force the compiler to generate lambda as a function pointer rather than closure by adding + in front of it, as shown above. Higher-Order Returning Lambda Functions C++ xxxxxxxxxx 1 13 1 const auto less_than = [](auto x) { 2 return [x](auto y) { 3 return y < x; 4 }; 5 }; 6 7 int main(void) 8 { 9 auto less_than_five = less_than(5); 10 std::cout << less_than_five(3) << std::endl; 11 std::cout << less_than_five(10) << std::endl; 12 return 0; 13 } Going a bit further, lambda functions can also return another lambda function. This will open the doors of endless possibilities for customization, code expressiveness, and compactibility (by the way, there is no word like this) of code. Constexpr Lambda Expression Since C++17, a lambda expression can be declared as constexpr. C++ xxxxxxxxxx 1 13 1 constexpr auto sum = [](const auto &a, const auto &b) { return a + b; }; 2 /* 3 is equivalent to 4 constexpr struct anonymous 5 { 6 template 7 constexpr auto operator()(T1 a, T2 b) const 8 { 9 return a + b; 10 } 11 }; 12 */ 13 constexpr int answer = sum(10, 10); Even if you don't specify constexpr , the function call operator will be constexpr anyway, if it happens to satisfy all constexpr function requirements. Closing Words I hope you enjoyed this article. I have tried to cover most of the intricacies around lambda with a couple of simple and small examples. You should use lambda wherever it strikes in your mind considering code expressiveness and easy maintainability like you can use it in custom deleters for smart pointers and with most of the STL algorithms.
May 8, 2020
· 50,054 Views · 4 Likes
article thumbnail
C++ Type Casting With Example for C Developers
In this article, we break down type casting in C++ for C developers, focusing on c-style, static, const, and reinterpret casts.
April 28, 2020
· 8,208 Views · 1 Like
article thumbnail
7 Advanced C++ Concepts You Should Know
Check out 7 concepts in C++ that should be on your radar, including RAII, return type resolvers, CRTP, and Virtual Constructors.
April 22, 2020
· 54,879 Views · 5 Likes
article thumbnail
What Exactly Nullptr Is in C++?
In this article, we discuss some basics behind nullptr in C++, including what it is, why it's useful, and when we can use it.
April 16, 2020
· 48,348 Views · 3 Likes

Comments

Open Closed Principle: SOLID as a Rock

May 21, 2020 · Vishal Chovatiya

Yeah, I know. But that's something automatic. There is no way I can change that.
Your suggestion would be helpful here.

What Is a Design Pattern?

May 21, 2020 · Vishal Chovatiya

Agree 100%.

That's why the article starts with "After hitting a certain level of experience and spending quite enough time.....".

Even I have learned all this after 3 yr of experience.

User has been successfully modified

Failed to modify user

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: