在堆上创建实例并保持多态性,这将给出正确的答案:

class Father
{
    public:

        virtual void Say()
        {
            cout << "Father say hello" << endl;
        }
};


class Son : public Father
{
    public:
        void Say()
        {
            cout << "Son say hello" << endl;
        }
};

int main()
{
    std::vector<Father*> v;
    std::cout << 1 << std::endl;

    for(int i(0); i<5; i++)
    {
        auto p = new Son();    ---------------on heap
        v.emplace_back(p);
    }
    for(auto p : v)
    {
        p->Say();
    }
}

但是,当我想在堆栈上创建一个实例时,似乎并不容易:

版本1:
class Father
{
    public:

        virtual void Say()
        {
            cout << "Father say hello" << endl;
        }
};


class Son : public Father
{
    public:
        void Say()
        {
            cout << "Son say hello" << endl;
        }
};


int main()
{
    std::vector<Father> v;
    for(int i(0); i<5; i++)
    {
        auto o = Son();    ---------------on stack
        v.emplace_back(o);---------------now "o" is cast to Father type
    }

    for(auto o : v)
    {
        o.Say();------------------------only output "Father say hello"
    }
}

和版本2:
class Father
{
    public:

        virtual void Say()
        {
            cout << "Father say hello" << endl;
        }
    };


class Son : public Father
{
    public:
        void Say()
        {
            cout << "Son say hello" << endl;
        }
};


int main()
{
    std::vector<Father*> v;
    for(int i(0); i<5; i++)
    {
        auto p = &Son();    --------------On the stack
        v.emplace_back(p);---------------Now "o" is cast to Father type
    }

    for(auto p : v)
    {
        p->Say();------------------------Since "p" now is a Wild pointer, it'll fail too
    }
}

这个可以解决吗?还是仅仅是一个死胡同:如果我想使用多态性,那么我必须在堆上创建一个对象。

最佳答案

这是一个反复出现的问题/难题:您可以牺牲一些样板代码来维护值语义。这是这种想法的最小工作示例:

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

class Father
{
 protected:
  struct Father_Interface
  {
    virtual void
    Say() const
    {
      std::cout << "Father say hello" << std::endl;
    }
  };

  using pimpl_type = std::shared_ptr<const Father_Interface>;
  pimpl_type _pimpl;

  Father(const Father_Interface* p) : _pimpl(p) {}

 public:
  Father() : Father{new Father_Interface{}} {}

  void Say() const { _pimpl->Say(); }
};

class Son : public Father
{
 protected:
  class Son_Interface : public Father_Interface
  {
    void
    Say() const override
    {
      std::cout << "Son say hello" << std::endl;
    }
  };

 public:
  Son() : Father{new Son_Interface{}} {}

  Son& operator=(const Father&) = delete; // fight against object slicing
};

int
main()
{
  std::vector<Father> v;

  v.emplace_back(Father());
  v.emplace_back(Son());
  v.emplace_back(Father());

  for (const auto& v_i : v)
  {
    v_i.Say();
  }
}

打印:



您还可以阅读以下内容:
  • Sean Parent's better-code-runtime-polymorphism
  • discussion about its usage
  • 10-05 22:40