📜 ⬆️ ⬇️

Say a word about poor C ++ API!

I had a desire to write about the C ++ API for a long time, and finally I had a quiet evening. By occupation, I and my guys are writing C ++ code for C ++ and Python programmers, a common core of functionality that is used in all of our company's products. Of course, this implies that the code must have an intuitive API, with common logic for both low-level C ++ and high-level Python, regardless of the different interpretations in the languages ​​of some basic constructs. I have written a lot about combining C ++ and Python earlier in articles about Boost.Python , now I am very grateful to the architecture and logic of the Python language, I understood and learned a lot in C ++ thanks to the experience of building a common API for these two such different languages, but now it's only about C ++, about the API, and what such a brutal, flexible language allows you to do with the interface of your wonderful library, if you ignore a number of important features of the C ++ language.

Present perfect coninuous


So, in the yard in 2014. The C ++ language (unlike its ancestor, a subset of the C language) has all the potential of a high-level language, which for many years has been nothing more than a potential. If a developer lacks something high-level, he will have to either invent something of his own, or try to find a ready-made solution, the benefit of sources of ready-made code is more than enough. This is also the good old STL, which in C ++ 11 is a bit darned and updated, it is a monster Boost, with heterogeneous libraries of varying degrees of readiness, there is also Qt with its interface and not only buns, but also a sea of ​​freely distributed software with different degrees contagion licenses. I will not compare the richness of C ++ libraries with libraries for Java and Python languages, nevertheless, languages ​​solve various problems, but it is obvious to everyone that it’s impossible to write something high-level without hard porn without spending too much time on C ++. So, sooner or later, having defined a niche, any C ++ developer writes for himself or for society, perhaps for colleagues, some common functionality, combining the mixed colors of the API set into a single coherent structure, in the search for his own Zen API design. There are, of course, people who prefer only to use libraries, write code for which they are paid, not interested in the beauty of building a software interface, exchanging it for worldly bustle, but this is not about them ... This article is for reaching for the light of true design of an excellent C ++ language API, Well, a little for those who are forcibly attracted to this light by the ears.

Classes


Oddly enough, but the classes are the weakest link in your API, if you want to make the interface of your library as transparent and predictable as possible. And even without taking into account the templates of these classes themselves. If you plunge into history a bit, then a class in C ++ is just an add-on to a struct in the C language. It contains all its fields by value, that is, it is nothing more than the totality of its fields with some OOP superstructure. Anyone who has ever dealt with Managed C ++ extensions to the C ++ language for the .NET platform, remember that classes can refer to their data by reference, or by reference. We will not discuss the horrors of the subtleties of the interaction of the C ++ language with the .NET framework, just note that in ordinary C ++ class data is always stored by value, even if this value is a link or pointer. So we are not very far from the C language, in which even the arguments to the function are passed by value and without options, if you want a link, pass the pointer. All this has indisputable advantages when placing temporary variables on a stack and the same data placement by value is probably the biggest problem with the architecture of a more or less high-level library implying intensive development, the release of new versions and a compatible software interface with each subsequent version. It doesn’t matter how you call classes, namespaces, methods and fields, the main thing is that you don’t need to know everything that you don’t need to know to .cpp or. cxx files and look at the implementation details) there’s nothing in the header file except for the API, if possible you should even remove all unnecessary #include, replacing with a forward declaration all the types used by reference ...
... including the data type of the class itself!
Yes Yes Yes! If it is possible to keep class data by reference, the data can be declared as a separate class without being implemented in a header file and put it entirely into a .cpp file with method implementation. That is, your class's API comes down to the following scheme:

//       SOME_API  import / export   ( !) //           API ( ,   SOME_API) class SOME_API something { public: //   ,    private: class data; //     ,     SDK,   ,      std::shared_ptr<data> m_data; //   ,     copy-on-write       }; 

')
The analogue of this code will be in your header file regardless of the extension: .h, .hpp, .hxx, or none at all. Naming is not so important here as the principle is important. Regardless of the filling of the class something :: data, we can not change the file with the API of the class something, more precisely without losing compatibility with its previous versions. But that's not all! © The classic approach with conventional storage hides in itself a whole brood of underwater rocks, on which we are carried by the course of the C ++ language with the behavior of the objects of your class by default.
To fully experience the beauty of storage by value, consider a small example:

 //       SOME_API  class person { public: //           const (     ) void set_name(std::string const& name); // -     ,   STL  MS  std::string   //   ,    copy-on-write,    std::string const& get_name() const; //     vector of child,     ,    //            m_children,     std::vector<person>& get_children(); //           ,       API //       add_child, get_child  .. std::vector<person> const& get_children() const; private: std::string m_name; // -  ,   person std::vector<person> m_children; //   ,     -  }; 


So what do we see here? The default constructor, which is sometimes harsh on POD types, is generated quite tolerable here, since the fields are standard STL containers, they have everything fine with initialization by default. In general, you should keep in mind that the constructors have the property to be generated: the default constructor, the copy constructor and in C ++ 11 also the displacement constructor, the copy operator is also generated and for the C ++ 11 displacement operator.
And if for initialization and movement here everything is clean thanks to STL, then with copying thanks to the same STL containers we will get the recursive copy hell.
Simple operation:

 person neighbour = granny; 

can lead to a hell of a headache for a hapless developer using your person class. Imagine that in the granny variable there is a built object of a certain grandmother with rich offspring, she has a lot of children and for each of the children there are also an order of magnitude more grandchildren. By all the rules, all these wonderful descendants of the grandmother will begin to clone like amoebas into a neighbor object. It will certainly be safe for your grandmother, in terms of Zen C ++ and STL containers, but it is completely unsafe for her psyche, and to optimize the performance of basic operations when working with your class is also very, very bad.
A careless developer will say: “oh, come on, they will understand, not small ones,” and unhappy library users will think how to take that same vector inside each object, which recursively complicates the problem of implicit copying. And most likely they will find another library that is better designed, and works more transparently and predictably.
Unexpected behavior with obvious operations is a headache for the developer of the functional and the API designer, and certainly not for the unfortunate user of their library. In the extreme case, experienced developers will bypass this problem by putting such dangerous classes in wrappers with smart pointers, but in general this cannot be done. Let's cure grandmother and her descendants from synchronous amebic division. Do not leave it here in this form!

 //     class person { public: //     -,      person(); //  ,    void set_name(std::string const& name); //      // (       !) std::string const& get_name() const; //      // (       !) std::vector<person>& get_children(); //       // (       !) std::vector<person> const& get_children() const; private: class data; //   double dispatch   class data  protected,     std::shared_ptr<data> m_data; //     ,    }; //      ,     class person::data { public: void set_name(std::string const& name); std::string const& get_name() const; std::vector<person>& get_children(); std::vector<person> const& get_children() const; private: std::string m_name; std::vector<person> m_children; }; //     person::person() : m_data(new data) //    , . .     { } //    person    person::data //   -  ,       //  : void person::set_name(std::string const& name) { //  ,      m_data->set_name(name); //    operator->    ,    } 


So grandmother stopped copying. Totally. Which is also not entirely correct in the C ++ concept, we shall deal with this separately. In principle, you can take the Java-style as the basis and transfer all such harsh values ​​by reference and only by reference, but this means deceiving a user of your library in a situation where you can avoid deceiving it. What prevents us from copying this grandmother's data only when the data changes?

Copy-on-write


The method of copying when changing is quite simple and you can implement it quite quickly yourself, moreover, thread-safe (provided that the implementation of std :: shared_ptr of the standard C ++ library is thread-safe). The essence of the Cow method is as follows, while the object is passed to the methods as const this, the data is divided between all copies of the object generated from the same data. However, as soon as this becomes non-constant, any of the methods (there are true exceptions) that are not marked as const first check std :: shared_ptr :: is_unique () and if more than one object refers to the same data, we detach our unique a copy of the general data and its rules. In principle, you can even do without a mutex, in the worst case, once again copy the object, which is not fatal for a test example in explaining this topic. This mechanism is implemented the easiest way through operator-> overloading for const and the non-const case of this object of the intermediate template class, which is template-based, since the mechanism is general. This intermediate template looks like this:

 //   !     ,   ! template <class data> class copy_on_write { public: //   ,      ,    data const* operator -> () const; //  ,    //      ,  ""     data* operator -> (); private: mutable std::shared_ptr<data> m_data; // mutable       const  void ensure_initialized() const; //    void ensure_unique(); //    }; //    template <class data> data const* copy_on_write<data>::operator -> () const { ensure_initialized(); //       nullptr return m_data.get(); //        const- } template <class data> data* copy_on_write<data>::operator -> () { ensure_unique(); // ,         return m_data.get(); //           } template <class data> void copy_on_write<data>::ensure_initialized() const { if (!m_data) { m_data.reset(new data); //    ,      type_traits    } } template <class data> void copy_on_write<data>::ensure_unique() { ensure_initialized(); //        if (!m_data.unique()) //  unique()   std::shared_ptr    { m_data.reset(new data(*m_data)); //        } } 

All that remains is to enable our person class to live for its own pleasure, create with impunity vectors of descendants of any length (they will be uninitialized before the first access to the data), copy, pass by value into functions (no const & need, let it be a bit more expensive) ), return as a result, too, by value (again, no const & and implicit errors due to this!) But the most important thing is that when we start changing the data of an object, only the object that is being modified is copied from the recursive copy It will become only an appearance!
So, person, live life to the fullest and do not deny yourself anything:

 class person { public: //   ,     ! private: class data; //      ,       API //              copy_on_write<data> m_data; }; 

A small explanation for all who have not yet understood what has changed for the copy operation. The fact is that all elements of the copy vector will refer to the same data as the elements of the source vector. If suddenly one of the elements starts to change, he will immediately unhook his data by making his unique copy. Therefore, a copy of the ancestor will not be so hard, although by itself, copying a vector can have quite serious overhead costs.

Constancy when calling method


Of course, the method of issuing a reference to a vector is an evil, extremely unfortunate solution for the Copy-on-write model, especially by overloading the method for const and non-const this. Just because implicitly there can be copying where non-constant overload is implicitly used. After all, the user of your API is not obliged to take care of the constancy of its variable, for example, starting a variable on the stack, the developer will receive a non-constant variable. Therefore, you need to carefully monitor that the fate of copying objects of your class does not depend on constancy. At least let it be obvious.

 class person { public: void set_name(std::string const& name); //  ,        std::string get_name() const; //    std::string      API   int get_child_count() const; //           person get_child(int index) const; //    ,        void add_child(person); //   ,     void set_child(int index, person const& child); //    person      private: class data; //      ,       API //              copy_on_write<data> m_data; }; 

So, we have an obvious class interface, instances of which can be easily created and copied in large quantities, and the implementation can be changed at least every day without changing the header file.

Compile time when using your API


As a bonus, we get a quicker compilation, simply because the field declaration person :: data is rendered in a separate file hidden in the implementation and there is no need to compile #include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .
  #include ,           person .     std::string    forward declaration,         #include ,        .      : 

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .
#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .

#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .

#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .
  #include ,           person .     std::string    forward declaration,         #include ,        .      : 

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .
#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .
  #include ,           person .     std::string    forward declaration,         #include ,        .      : 

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .
#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .
  #include ,           person .     std::string    forward declaration,         #include ,        .      : 

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .
#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .
  #include ,           person .     std::string    forward declaration,         #include ,        .      : 

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .
#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .

#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .

#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .

#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .

#include , person . std::string forward declaration, #include , . :

// <stdfwd> namespace std { template <typename char_type> class allocator; template <typename char_type> struct char_traits; template <typename char_type, typename traits_type, typename allocator_type> class basic_string; // forward declaration std::string typedef basic_string<char, char_traits<char>, allocator<char>> string; // forward declaration std::wstring typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring; // , #include <cstddef> std::nullptr_t typedef decltype(nullptr) nullptr_t; }

. , C++ API , , . , , , . API.


" " . , : , . , , :
1) API ( , ... , ?)
2) ,
3) - API, .

, .
:

1. , - , - , -, interface- ( ). - . , :

std::unique_ptr<IAmUselessInterface> something = UserUsefulFactory::CreateSomethingLessUseless<DerivedUsefulClass>(arguments);
, , , double dispatch , , - , private. C++ , - , API -.

2. . . 1 . , !.. , , , , - - ! 1 :

std::unique_ptr<I> something = ::Instance().<>( ::Instance().<>(42)); // : (<>(42));
3. . : , , . , : - . , API, - - -, , . , C++ , , - . , , API .

Boost.Python. object namespace boost::python , Python C++, PyObject* , . PyObject* object ( None - NULL - Python). , , boost::python::dict boost::python::object . , , , , dict object .

double dispatch - , , - , ++ . , :

class person { public: // - protected: class data; data& get_data_reference(); data const& get_data_const_reference() const; private: copy_on_write<data> m_data; }; class VIP : public person { public: // protected: class data; // VIP::data - person::data };
:

person president = VIP("mr. President");
, , -.
, , , , . , - !


API, , .
, --API, , ?
! - , - , . , , !


(Copy-on-write).
(Double dispatch)
- , , .

Source: https://habr.com/ru/post/229327/


All Articles