Refer to c++ primer
Refer to Matsumoto's procedural world
- Object oriented has three characteristics: Abstract encapsulation, inheritance and polymorphism
- Abstract encapsulation controls the access of data and methods through private and public, and divides the implementation and call
Inheritance (c + + as an example)
Data and common method inheritance
class Base { public: string name; Base() { name = "base class"; } void print() { cout << this->name << endl; } }; class Sub : public Base { public: string name; Sub() : Base() { name = "sub class"; } void print() { cout << name << endl; cout << Base::name << endl; Base::print(); } }; int main() { Sub obj; cout << obj.Base::name << endl; obj.Base::print(); cout << obj.name << endl; obj.print(); return 0; } // output //base class //base class //sub class //sub class //base class //base class
- In the inheritance relationship, the derived class will directly copy the data sample of a base class, even if the fields are the same
- In the inheritance relationship, the base class is a common method. It inherits directly and is determined at compile time
- In the inheritance relationship, the virtual method of the base class overrides the implementation of the override base class according to the specific derived class, and is bound dynamically
- Based on the determination at compile time, the base class method cannot access the derived class data fields and methods through this, etc
- Based on the determination at compile time, it should be clearly pointed out that the derived class accesses the data fields and methods of the base class
- Sub inherits the print of base. Base::print has determined that the name of base is accessed during compilation, and the name of sub cannot be accessed
- public Base describes whether the print and name inherited by the Sub can be accessed externally through the instance. Replace it with a private compilation error
- When the Sub contains duplicate data name and method print, if you call the Base class, you should use Base:: to specify it
Multiple inheritance
- Multiple inheritance pain points, complex class relationship, fuzzy priority, and conflict when multiple parent classes contain the same method
- To solve the problem of multiple inheritance, c + + should specify the parent class explicitly
java single inheritance multiple interfaces
- Extensions is used for implementation inheritance and implements is used for specification inheritance. The implementation of specification interface is generally based on composition delegation to the instance implementing the interface
Mixin
- When the c + + multi inheritance parent class has the same name, it should be clearly specified to use the parent class. java adopts an interface to realize multi inheritance. It really needs to be realized through composite delegation. In some cases, Mixin programming skills can be used
- Mixin class should be abstract, single and general, used to extend the function of the successor, and its own instantiation is meaningless
- python system level examples ThreadingTCPServer, ThreadingMixIn, ForkingMixIn, TCPServer, UDPServer
# In the scenario of serialization string, the association between students and serialization is not obvious class JsonMixin(object): """Only consider int, str, dict, class """ def to_json(self): def help(obj): result = [] for k, v in obj.items(): if isinstance(v, str): result.append(f'"{k}":"{v}"') elif isinstance(v, int): result.append(f'"{k}":{str(v)}') elif isinstance(v, dict): result.append(f'"{k}":{help(v)}') elif isinstance(v, object): result.append(f'"{k}":{help(v.__dict__)}') return "{" + ",".join(result) + "}" return help(self.__dict__) class XmlMixin(object): """Only consider int, str, dict, class """ def to_xml(self): def help(tag, obj): result = f"<{tag}>" for k, v in obj.items(): if isinstance(v, str): result += f'<{k}>"{v}"</{k}>' elif isinstance(v, int): result += f'<{k}>{v}</{k}>' elif isinstance(v, dict): result += help(k, v) elif isinstance(v, object): result += help(k, v.__dict__) result += f"</{tag}>" return result return help(self.__class__.__name__, self.__dict__) class Attr(object): def __init__(self, addr, phone): self.addr = addr self.phone = phone class Student(JsonMixin, XmlMixin): def __init__(self, name, age, score, attr): self.name = name self.age = age self.score = score self.attr = attr swk = Student("Sun WuKong", 500, {"qi_shi_er_bian": 100, "huo_yan_jin_jing": 95}, Attr("Dongsheng Shenzhou Aolai Huaguo Mountain", "Call you Grandpa")) print(swk.to_json()) print(swk.to_xml())
- Regardless of the above examples or the system level examples mentioned earlier, Mixin should be generic and abstract. First, it can not contain too many data fields, but there are few scenarios in which the function is irrelevant to the data. It should be said that Mixin extends classes that conform to a certain structure
- If it is inheritance extension structure, or method and data are strongly dependent, traditional inheritance is more appropriate
- Because the dynamic language passes pointers to current instances such as self and this, it is easy to separate the Mixin function from the data
compare
- Based on c + + multi inheritance, how to implement the above functions? Each parent class is responsible for serializing its own data into strings
#include <iostream> #include <string> #include <vector> using namespace std; class People { public: string name; int age; People(string name, int age) : name(name), age(age) {} string to_json() { return "{\"name\":\"" + name + "\",\"age\":" + to_string(age) + "}"; } }; class Attr { public: string addr; string phone; Attr(string addr, string phone) : addr(addr), phone(phone) {} string to_json() { return "{\"addr\":\"" + addr + "\",\"phone\":\"" + phone + "\"}"; } }; class Score { public: string title; float score; Score(string title, float score) : title(title), score(score) {} string to_json() { return "{\"title\":\"" + title + "\",\"score\":" + to_string(score) + "}"; } }; class Student : public People, public Attr, public vector<Score> { public: Student(string name, int age, string addr, string phone) : People(name, age), Attr(addr, phone) {} void add_score(Score &s) { vector<Score>::emplace_back(s); } string to_json() { string result = "{\"people\":" + People::to_json() + ",\"attr\":" + Attr::to_json() + ",\"score\":["; for (auto s = vector<Score>::begin(); s != vector<Score>::end(); ++s) { result += s->to_json() + ","; } result = result.substr(0, result.size() - 1); result += "]}"; return result; } }; int main() { Student stu("Sun WuKong", 500, "Dongsheng Shenzhou Aolai Huaguo Mountain", "Call you Grandpa"); Score boss1("Seventy two changes", 100.0); Score boss2("piercing eye", 95.5); stu.add_score(boss1); stu.add_score(boss2); cout << stu.to_json() << endl; return 0; } // output // {"people":{"name": "Monkey King", "age":500},"attr":{"addr": "Dongsheng Shenzhou Aolai guohuaguo mountain", "phone": "call you Grandpa"}, "score":[{"title": "seventy-two changes", "score":100.000000},{"title": "golden eyes", "score":95.500000}]}
- If RTTI supports obtaining class data fields at runtime, the Mixin style pseudo code is as follows
#include <iostream> #include <string> #include <vector> #include <typeinfo> using namespace std; class JsonMixin { public: string to_json(void *obj) { // If the RTTI or reflection mechanism of the programming language supports obtaining types and class fields, it can be implemented here return ""; } }; class People { public: string name; int age; People(string name, int age) : name(name), age(age) {} }; class Attr { public: string addr; string phone; Attr(string addr, string phone) : addr(addr), phone(phone) {} }; class Score { public: string title; float score; Score(string title, float score) : title(title), score(score) {} }; class Student : public People, public Attr, public vector<Score>, public JsonMixin { public: Student(string name, int age, string addr, string phone) : People(name, age), Attr(addr, phone) {} void add_score(Score &s) { vector<Score>::emplace_back(s); } string to_json() { // return typeid(*this).name(); return JsonMixin::to_json(this); } }; int main() { Student stu("Sun WuKong", 500, "Dongsheng Shenzhou Aolai Huaguo Mountain", "Call you Grandpa"); Score boss1("Seventy two changes", 100.0); Score boss2("piercing eye", 95.5); stu.add_score(boss1); stu.add_score(boss2); cout << stu.to_json() << endl; return 0; }
Supplement Mixin wiki explanation
https://encyclopedia.thefreedictionary.com/mixin
- In an object-oriented programming language, Mixin is a class that contains methods for other classes, not necessarily the parent of these other classes. How these other classes access Mixin depends on the language
- Mixin encourages code reuse, which can be used to avoid inheritance ambiguity (diamond problem) caused by multiple inheritance, or to solve the problem of lack of support for multiple inheritance in the language
- Mixin is a language concept, not necessarily a syntax feature, which allows programmers to inject some code into classes. Mixin programming is a software development style in which functional units are created in one class and then mixed with other classes
- The mixin class acts as a parent class and contains the required functionality. Subclasses can then inherit or simply reuse this functionality, but not as a means of specialization. Mixin will export the required functions to subclasses without creating a strict and single "is a" relationship, which is an important difference between mixin and the concept of inheritance
- benefit
- It provides a multiple inheritance mechanism that allows a class to use common functions from multiple classes without the complex semantics of multiple inheritance
- Code reusability, mixin is useful when programmers want to share functionality between different classes. Instead of repeating the same code over and over again, you can simply group common functionality into a mixin and include it in each class that needs it
- Mixins only allows you to inherit and use the required attributes from the parent class, not necessarily all the attributes from the parent class