代码之家  ›  专栏  ›  技术社区  ›  cchampion

虚函数问题

  •  0
  • cchampion  · 技术社区  · 15 年前
    #include "stdafx.h"
    #include <iostream>
    #include <vector>
    #include <string>
    
    class Helper 
    {
    public:
        Helper() { init(); }
        virtual void print() {
            int nSize = m_vItems.size();
            std::cout << "Size : " << nSize << std::endl;
            std::cout << "Items: " << std::endl;
            for(int i=0; i<nSize; i++) {
                std::cout << m_vItems[i] << std::endl;
            }
        }
    protected:
        virtual void init() { m_vItems.push_back("A"); }
        std::vector<std::string> m_vItems;
    };
    
    class ItemsHelper : public Helper
    {
    public:
        ItemsHelper() { }
    protected:
        virtual void init() { 
            Helper::init();
            m_vItems.push_back("B");
        }
    };
    
    int _tmain(int argc, _TCHAR* argv[]) {
        ItemsHelper h;
        h.print();
    }
    

    Helper::init() 函数,然后向向量添加第二项。问题是,不会调用ItemsHelper::init,而是调用基类init函数。

    我希望调用ItemsHelper::init函数,我可以通过在ItemsHelper构造函数中而不是在基类中调用init函数来实现这一点。 但是,问题是 ,是否有更好的方法来实现这一点,并且仍然在基类中保留对init()的调用?因为如果我想创建一个Helper对象而不是ItemsHelper,那么init函数将永远不会被调用。

    4 回复  |  直到 15 年前
        1
  •  7
  •   CB Bailey    15 年前

    在基类构造函数中,尚未构造派生类,因此派生类上的重写函数尚不可用。在某个地方有一个FAQ条目。。。我找不到。

    最简单的解决办法就是把 .push_back("A") init 进入 Helper 构造函数和 .push_back("B") 进入 ItemsHelper 构造器。这似乎做了你正试图做的事情,并减少了不必要的事情 虚拟功能。

        2
  •  4
  •   Community CDub    7 年前

    请注意,在构造函数中,虚拟函数并不像“预期”那样工作!

    Helper() { init(); }
    

    init() 将始终调用当前类(Helper)的“init”,即使它被标记为virtual。

    编辑: 有一个 similar question 就这样。

        4
  •  2
  •   BatchyX    15 年前

    问题是虚拟函数的工作方式与您认为的构造函数不同。构造ItemsHelper时,首先构造基类帮助器。在其构造函数中,对象的类型是Helper,因此对init的调用调用Helper::init()。然后调用ItemsHelper构造函数。无法从基类构造函数调用派生类函数。最好是在构建ItemsHelper对象后调用init()。