zoukankan      html  css  js  c++  java
  • C++的另一种抽象流派:bind+function

      C++一直提供了基于多态的抽象设计方式,让我们摆脱了C语言中type+callback+void*抽象方式,从而可以将数据与方法封装在一起,更清晰的描述代码。

      C++的抽象基于多态实现,一个简单的例子:

    #include <iostream>
    class A
    {
    public:
        virtual ~A()
        {
            /* std::cout << __FUNCTION__ << std::endl; */
        }
        virtual void Func(void) = 0;
    };
    
    class B: public A
    {
    public:
        virtual ~B()
        {
            std::cout << __FUNCTION__ << std::endl;
        }
        virtual void Func(void)
        {
            std::cout << "B::Func" << std::endl;
        }
    };
    
    class C: public A
    {
    public:
        virtual ~C()
        {
            std::cout << __FUNCTION__ << std::endl;
        }
        virtual void Func(void)
        {
            std::cout << "C::Func" << std::endl;
        }
    };
    
    void IDoNotKnowAnyDetail(A *base)
    {
        base->Func();
        delete base;
    }
    
    int main(int argc, char *const argv[])
    {
        A *pb = new B();
        A *pc = new C();
        IDoNotKnowAnyDetail(pb);
        IDoNotKnowAnyDetail(pc);
        return 0;
    }

    输出:

    B::Func
    ~B
    C::Func
    ~C

      A是抽象基类, B和C分别实现Func, 然后有一个IDoNotKnowAnyDetail函数依赖了A抽象, 对细节不知情.

      这是目前C++, 无论是经典教材还是大学教材里都讲的基础知识, 那么bind+function如何达到类似的抽象能力呢, 看下面的代码:

    #include <iostream>
    #include <algorithm>
    #include <tr1/memory>
    #include <tr1/functional>
    
    class B
    {
    public:
        ~B()
        {
            std::cout << __FUNCTION__ << std::endl;
        }
        void FuncB(void)
        {
            std::cout << __FUNCTION__ << std::endl;
        }
    };
    
    class C
    {
    public:
        ~C()
        {
            std::cout << __FUNCTION__ << std::endl;
        }
        void FuncC(void)
        {
            std::cout << __FUNCTION__ << std::endl;
        }
    };
    
    void IDoNotKnowAnyDetail(std::tr1::function<void ()> func)
    {
        func();
    }
    
    int main(int argc, char *const argv[])
    {
        std::tr1::function<void ()> func_b = std::tr1::bind(&B::FuncB, std::tr1::shared_ptr<B>(new B()));
        std::tr1::function<void ()> func_c = std::tr1::bind(&C::FuncC, std::tr1::shared_ptr<C>(new C()));
        IDoNotKnowAnyDetail(func_b);
        IDoNotKnowAnyDetail(func_c);
        return 0;
    }

    输出:

    FuncB
    FuncC
    ~C
    ~B

      代码尽量和上面实现相似, 以便比较. 可以看到IDoNotKnowAnyDetail函数的参数是function<void ()>, 但它依旧表现出了与多态实现一样的输出, 与多态版本相比还少实现了一个类A, 很有意思.

      bind+function版本我使用了shared_ptr取代了raw指针, 在多线程环境下线程间传递func_b, func_c是可以无需考虑内存释放的, 对象会随着function的析构而一起释放, 这一点也比较实用.

      

      两种风格在完成工作的能力方面暂时没感觉到什么差别, 但bind+function是一种回归C风格的方案, 但同时保留了数据与方法的封装性, 并不是一种倒退.

      性能方面, 多态风格由于虚函数的原因, 性能稍有损耗但根本不足为患, bind+function风格性能妥妥的, 同时避免了多态引入的继承体系, 一定程度降低代码复杂度.

      可读性方面, 我认为多态实现更易读, 因为它基于面向对象的语义, 还是符合人类习惯的, bind+function风格导致多个实现类彼此没有明显关联, 也许会稍微阻碍一下理解.

      实现方面, bind+function的实现是比较高端, 照我的意思说是挺暗黑的(C++这方面的难度与复杂度我真无心深究了), 但并不耽误使用, 毕竟C++11已经纳入标准, 即便我们不愿意去理解底层实现, 但一个定义和行为明确的黑盒利器依旧是我们值得选择的. 多态实现就不多说了, 大家都有经验.

      

      代码风格方面, 我认为还是统一而不要混用, 否则对项目维护可能是个小灾难.

      

  • 相关阅读:
    join命令
    参与者模式
    字符串中的第一个唯一字符
    Git与SVN对比
    惰性模式
    .NET Conf 2020
    使用Github部署Azure应用服务
    Azure Terraform(一)入门简介
    打日志还能打出个线上Bug_ 太难了。。。
    让API并行调用变得如丝般顺滑的绝招
  • 原文地址:https://www.cnblogs.com/cppisnotbad/p/3239569.html
Copyright © 2011-2022 走看看