Skip to content

sean-parent Value Semantics and Concept-based Polymorphism

NOTE:

1、原文的内容不容易理解,并且非常冗长,我目前还是没有读懂,目前碰到的一个阻碍是"incidental data structures"这个概念,这个概念非常重要,我发现后续内容很多都是基于这个概念的,这是Sean Parent提出的,参见:

a、https://sean-parent.stlab.cc/presentations/2016-08-08-data-structures/2016-08-08-data-structures.pdf

b、https://github.com/sean-parent/sean-parent.github.io/blob/master/better-code/03-data-structures.md

2、后来我直接阅读它实现:

a、C++ Source

b、C++ Source (unique_ptr version)

意外发现我能够理解实现原理,通过实现我理解了"Value Semantics"、"Concept-based Polymorphism"的含义以及各自的实现方式,所以,我的主要笔记都放在了C++source 章节中,通过其中的内容,大致理解了Value Semantics and Concept-based Polymorphism。

Outline of Talk

1、Defining Value Semantics

2、“Polymorphic Types”

3、Demo of Photoshop History

4、Implement History

Disclaimer

In the following code, the proper use of header files, inline functions, and namespaces are ignored for clarity

Client、library、guideline

NOTE: 这一段,作者使用一个简单的例子来说明client、library的概念,后面的demo程序都是基于client、library的概念的

client

int main()
{
    document_t document;
    document.emplace_back(0);
    document.emplace_back(1);
    document.emplace_back(2);
    document.emplace_back(3);
    draw(document, cout, 0);
}

library

using object_t = int;
void draw(const object_t &x, ostream &out, size_t position)
{
    out << string(position, ' ') << x << endl;
}
using document_t = vector<object_t>;
void draw(const document_t &x, ostream &out, size_t position)
{
    out << string(position, ' ') << "<document>" << endl;
    for (const auto &e : x)
        draw(e, out, position + 2);
    out << string(position, ' ') << "</document>" << endl;
}

完整程序

#include <iostream>
#include <vector>
using namespace std;

using object_t = int;
void draw(const object_t &x, ostream &out, size_t position)
{
    out << string(position, ' ') << x << endl;
}
using document_t = vector<object_t>;
void draw(const document_t &x, ostream &out, size_t position)
{
    out << string(position, ' ') << "<document>" << endl;
    for (const auto &e : x)
        draw(e, out, position + 2);
    out << string(position, ' ') << "</document>" << endl;
}
int main()
{
    document_t document;
    document.emplace_back(0);
    document.emplace_back(1);
    document.emplace_back(2);
    document.emplace_back(3);
    draw(document, cout, 0);
}
//g++ --std=c++11 -Wall -pedantic test.cpp && ./a.out

NOTE: 输出如下:

<document>
  0
  1
  2
  3
</document>

guidelines

Write all code as a library:

1、Reuse increases your productivity. 2、Writing unit tests is simplified.

Polymorphism

What happens if we want the document to hold any drawable object?

library

class object_t
{
public:
    virtual ~object_t()
    {
    }
    virtual void draw(ostream&, size_t) const = 0;
};
using document_t = vector<shared_ptr<object_t>>;
void draw(const document_t &x, ostream &out, size_t position)
{
    out << string(position, ' ') << "<document>" << endl;
    for (const auto &e : x)
        e->draw(out, position + 2);
    out << string(position, ' ') << "</document>" << endl;
}

client

class my_class_t: public object_t
{
public:
    void draw(ostream &out, size_t position) const
    {
        out << string(position, ' ') << "my_class_t" << endl;
    }
    /* ... */
};
int main()
{
    document_t document;
    document.emplace_back(new my_class_t());
    draw(document, cout, 0);
}

完整程序

#include <iostream>
#include <vector>
#include <memory>

using namespace std;

class object_t
{
public:
    virtual ~object_t()
    {
    }
    virtual void draw(ostream&, size_t) const = 0;
};
using document_t = vector<shared_ptr<object_t>>;
void draw(const document_t &x, ostream &out, size_t position)
{
    out << string(position, ' ') << "<document>" << endl;
    for (const auto &e : x)
        e->draw(out, position + 2);
    out << string(position, ' ') << "</document>" << endl;
}

class my_class_t: public object_t
{
public:
    void draw(ostream &out, size_t position) const
    {
        out << string(position, ' ') << "my_class_t" << endl;
    }
    /* ... */
};
int main()
{
    document_t document;
    document.emplace_back(new my_class_t());
    draw(document, cout, 0);
}
//g++ --std=c++11 -Wall -pedantic test.cpp && ./a.out

NOTE: 输出如下:

<document>
  my_class_t
</document>

defects

NOTE:

1、上述第一条的解释让我明白了CppCoreGuidelines R.11: Avoid calling new and delete explicitly 的原因,在CppCoreGuidelines R.11: Avoid calling new and delete explicitly 中,收录了这个点

2、上述例子非常好的展示了: "polymorphic object container"这个topic,在Polymorphic-object-container章节进行了详细的说明。

Deep problem #1

Changed semantics of copy, assignment, and equality of my document

NOTE: 什么含义?是否是指由于引入了virtual,而导致object_t是一个polymorphic type,因此它的copy就涉及到了object slicing等问题

1、leads to incidental data structures

NOTE:什么是"incidental data structures"?参见:

1、https://sean-parent.stlab.cc/presentations/2016-08-08-data-structures/2016-08-08-data-structures.pdf

2、thread safety concerns

NOTE: 有什么thread safety concerns?