如何正确关闭?

时间:2013-03-02 21:51:42

标签: c++ shared-ptr

这可能是C ++编码标准中解释的关闭规则的情况,我想知道我是否正确地执行了此操作。我想知道因为我在切换功能中仍然有if子句。

A永远不会直接实例化,它始终是动态创建的BC,并通过指向A的(共享)指针统一处理。 foo根据是B还是C来切换并选择操作。

class A {
public:
  virtual ~A(){}
};

class B : public A {};
class C : public A {};

typedef std::shared_ptr<A> Aptr;
typedef std::shared_ptr<B> Bptr;
typedef std::shared_ptr<C> Cptr;


template<class T>
std::shared_ptr<T> get(const Aptr& pA) {
  return std::dynamic_pointer_cast< T >( pA );
}

void foo( const Bptr& pB ) {
  std::cout << "operate on B\n";
}

void foo( const Cptr& pC ) {
  std::cout << "operate on C\n";
}

void foo( const Aptr& pA ) {
  if ( auto x = get<B>(pA) ) {
    foo(x);
    return;
  }
  if ( auto x = get<C>(pA) ) {
    foo(x);
    return;
  }
  assert(!"oops");
}


int main()
{
  Aptr pA( new C );

  foo( pA );
}

我的问题是void foo( const Aptr& pA )是否可以更优雅地实施。这可能意味着没有if。投掷get并在这种情况下推荐foo

2 个答案:

答案 0 :(得分:2)

除非你有充分的理由否则(如果你有它们,你的代码没有显示它们),这在我看来就像通过虚函数实现的动态多态的典型用例:

class A 
{
public:
    virtual ~A() {}
    virtual void foo() = 0;
};

class B : public A 
{
    virtual void foo() 
    {
        std::cout << "operate on B\n";
    }
};

class C : public A 
{
    virtual void foo() 
    {
        std::cout << "operate on B\n";
    }
};

此外,在C ++ 11中,最好使用std::make_shared<>()来构建shared_ptr并进行裸new分配(同样,除非你有充分的理由否则):

int main()
{
    Aptr pA = std::make_shared<C>();
    pA->foo();
}

如果您有理由不使用虚函数并且喜欢不同的非侵入式多态,则可以将Boost.Variant与boost::static_visitor结合使用。这甚至不需要BC相关。

#include <boost/variant.hpp>
#include <memory>
#include <iostream>

class B /* ... */ {};
class C /* ... */ {};

// ...
typedef std::shared_ptr<B> Bptr;
typedef std::shared_ptr<C> Cptr;

struct foo_visitor : boost::static_visitor<void>
{
    void operator () (Bptr p)
    {
        std::cout << "operate on B\n";
    }

    void operator () (Cptr p)
    {
        std::cout << "operate on C\n";
    }
};

int main()
{
    boost::variant<Bptr, Cptr> ptr;
    ptr = std::make_shared<C>();

    foo_visitor v;
    ptr.apply_visitor(v);
}

这种方法与您选择的方法非常相似,除了Boost.Variant还确保您不会忘记为变体可能假设的每个值包含一个处理案例(在这种情况下,{{1} }和Bptr)。

答案 1 :(得分:1)

只需使用虚拟成员函数。没有替代真实的东西

class A {
public:
  virtual ~A(){}
  virtual void foo() = 0;
};

class B : public A {
public:
  virtual void foo() {
     std::cout << "operate on B\n";
  }
};

class C : public A {
public:
  virtual void foo() {
     std::cout << "operate on C\n";
  }
};

并选择一个好的C++ introductory book