C ++中静态多态性的动机是什么? [英] What is the motivation behind static polymorphism in C++?

查看:103
本文介绍了C ++中静态多态性的动机是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我了解静态多态性的机制,使用好奇地重复模板模式。我只是不明白什么是有益的。

I understand the mechanics of static polymorphism using the Curiously Recurring Template Pattern. I just do not understand what is it good for.

声明的动机是:


我们牺牲了动态多态性的一些灵活性速度

但是为什么要这么复杂 p>

But why bother with something so complicated like:

template <class Derived>
class Base
{
public:
    void interface()
    {
         // ...
         static_cast<Derived*>(this)->implementation();
         // ...
    }
};

class Derived : Base<Derived>
{
private:
     void implementation();
};

当你可以做:

class Base
{
public: 
    void interface();
}

class Derived : public Base
{
public: 
    void interface();
}



我最好的猜测是,代码中没有语义差异,只是一个良好的C ++风格的问题。

My best guess is that there is no semantic difference in the code and that it is just a matter of good C++ style.

Herb Sutter在 Exceptional C ++ style:Chapter 18 中写道:

Herb Sutter wrote in Exceptional C++ style: Chapter 18 that:


希望将虚拟函数设为私有。

Prefer to make virtual functions private.

这是好样式

在本指南的上下文中,第一个示例是良好,因为:

In the context of this guideline the first example is good, because:

在示例中的 void implementation()函数可以假装为虚拟,因为它是在这里执行类的自定义。

The void implementation() function in the example can pretend to be virtual, since it is here to perform customization of the class. It therefore should be private.

第二个例子是,因为:

我们不应该使用公共接口来执行自定义。

We should not meddle with the public interface to perform customization.

我的问题是:


  1. 我缺少静态多态性是什么?是关于良好的C ++风格吗?

  2. 应该什么时候使用?


推荐答案


静态多态性?这是关于好的C ++风格吗?

What am I missing about static polymorphism? Is it all about good C++ style?

静态多态性和运行时多态性是不同的东西,完成不同的目标。它们都是技术上的多态性,因为它们基于某种类型决定要执行哪一段代码。运行时多态性延迟绑定某事物的类型(因此运行的代码)直到运行时,而静态多态性在编译时完全解决。

Static polymorphism and runtime polymorphism are different things and accomplish different goals. They are both technically polymorphism, in that they decide which piece of code to execute based on the type of something. Runtime polymorphism defers binding the type of something (and thus the code that runs) until runtime, while static polymorphism is completely resolved at compile time.

这导致利弊为每个。例如,静态多态性可以在编译时检查假设,或者在不能编译的选项之间进行选择。它还向编译器和优化器提供大量信息,这些信息可以完全知道调用和其他信息的目标。但是静态多态性需要实现可供编译器检查每个翻译单元,可能导致二进制代码大小膨胀(模板是花式裤复制粘贴),并且不允许这些确定在运行时发生。

This results in pros and cons for each. For instance, static polymorphism can check assumptions at compile time, or select among options which would not compile otherwise. It also provides tons of information to the compiler and optimizer, which can inline knowing fully the target of calls and other information. But static polymorphism requires that implementations be available for the compiler to inspect in each translation unit, can result in binary code size bloat (templates are fancy pants copy paste), and don't allow these determinations to occur at runtime.

例如,考虑 std :: advance

template<typename Iterator>
void advance(Iterator& it, ptrdiff_t offset)
{
    // If it is a random access iterator:
    // it += offset;
    // If it is a bidirectional iterator:
    // for (; offset < 0; ++offset) --it;
    // for (; offset > 0; --offset) ++it;
    // Otherwise:
    // for (; offset > 0; --offset) ++it;
}

没有办法使用运行时多态性来编译。你必须在编译时作出决定。 (通常,您可以使用标记分派(例如。)

There's no way to get this to compile using runtime polymorphism. You have to make the decision at compile time. (Typically you would do this with tag dispatch e.g.)

template<typename Iterator>
void advance_impl(Iterator& it, ptrdiff_t offset, random_access_iterator_tag)
{
    // Won't compile for bidirectional iterators!
    it += offset;
}

template<typename Iterator>
void advance_impl(Iterator& it, ptrdiff_t offset, bidirectional_iterator_tag)
{
    // Works for random access, but slow
    for (; offset < 0; ++offset) --it; // Won't compile for forward iterators
    for (; offset > 0; --offset) ++it;
}

template<typename Iterator>
void advance_impl(Iterator& it, ptrdiff_t offset, forward_iterator_tag)
{
     // Doesn't allow negative indices! But works for forward iterators...
     for (; offset > 0; --offset) ++it;
}

template<typename Iterator>
void advance(Iterator& it, ptrdiff_t offset)
{
    // Use overloading to select the right one!
    advance_impl(it, offset, typename iterator_traits<Iterator>::iterator_category());
}  

同样,有些情况下你真的不知道编译时的类型时间。考虑:

Similarly, there are cases where you really don't know the type at compile time. Consider:

void DoAndLog(std::ostream& out, int parameter)
{
    out << "Logging!";
}

这里, DoAndLog 不知道任何关于实际的 ostream 实现 - 它可能不可能静态确定将传递什么类型。当然,这可以变成一个模板:

Here, DoAndLog doesn't know anything about the actual ostream implementation it gets -- and it may be impossible to statically determine what type will be passed in. Sure, this can be turned into a template:

template<typename StreamT>
void DoAndLog(StreamT& out, int parameter)
{
    out << "Logging!";
}

但这会强制 DoAndLog 在头文件中实现,这可能是不切实际的。它还要求StreamT的所有可能的实现在编译时可见,这可能不是真的 - 运行时多态性可以在DLL或SO边界上工作(虽然这不推荐)。

But this forces DoAndLog to be implemented in a header file, which may be impractical. It also requires that all possible implementations of StreamT are visible at compile time, which may not be true -- runtime polymorphism can work (although this is not recommended) across DLL or SO boundaries.


何时使用?什么是一些准则?

When should it be used? What are some guidelines?

这就像有人来找你说,当我写一句话,句子还是简单句子?还是一个画家说我应该总是使用红漆还是蓝漆?没有正确的答案,没有一套可以盲目遵循的规则。您必须查看每种方法的优缺点,并决定哪些最佳地图到您的特定问题域。

This is like someone coming to you and saying "when I'm writing a sentence, should I use compound sentences or simple sentences"? Or perhaps a painter saying "should I always use red paint or blue paint?" There is no right answer, and there is no set of rules that can be blindly followed here. You have to look at the pros and cons of each approach, and decide which best maps to your particular problem domain.

至于CRTP,大多数使用情况是允许基类提供派生类的东西;例如Boost的 iterator_facade 。基类需要有 DerivedClass operator ++(){/ * Increment和return * this * /} inside - 在成员函数中指定的引用签名

As for the CRTP, most use cases for that are to allow the base class to provide something in terms of the derived class; e.g. Boost's iterator_facade. The base class needs to have things like DerivedClass operator++() { /* Increment and return *this */ } inside -- specified in terms of derived in the member function signatures.

它可以用于多态性,但我还没有看到太多。

It can be used for polymorphic purposes, but I haven't seen too many of those.

这篇关于C ++中静态多态性的动机是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆