0

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

A永远不会被直接实例化,它总是要么B动态C创建,要么通过指向A. foo根据是 anB还是来切换和选择操作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

4

2 回答 2

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<>()的 a 构造(同样,除非您有充分的理由不这样做):shared_ptrnew

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 还确保您不会忘记为变体可能假设的每个值(在本例中为BptrCptr)包含一个处理案例。

于 2013-03-02T21:54:58.370 回答
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++ 入门书

于 2013-03-02T21:55:41.590 回答