繁体   English   中英

在基类向量上调用虚函数

[英]Calling a virtual function on a vector of base classes

我创建了一些代码来重现问题:

#include "stdafx.h"
#include <iostream>
#include <vector>

class A
{
protected:
    int m_X;
public:
    A() { 
        std::cout << "in A ctor" << std::endl; 
        m_X = 0;
    }
    virtual void printX(){ std::cout << "in A " << m_X << std::endl; }
};

class B : public A
{
public:
    B() {
        std::cout << "in B ctor" << std::endl; 
        m_X = 1;
    }
    virtual void printX(){ std::cout << "in B " << m_X << std::endl; }
};

class As
{
public:
    void AddA( const A &a ){ m_As.push_back( a ); }
    void PrintXs()
    {
        for ( auto a : m_As )
        {
            a.printX();
        }
    }
private:
    std::vector<A> m_As;
};

int _tmain(int argc, _TCHAR* argv[])
{
    As as;
    B b;
    as.AddA( b );
    as.PrintXs();
    system("pause");
    return 0;
}

这个的输出是:

在演员

在 B ctor

在 A 1

我想要“在 B 1”而不是“在 A 1”。 我确信我对虚拟的理解是有缺陷的。 我必须如何更改代码以调用 B PrintX()? 请注意,会有其他类从 A 继承,所以我真的不想编写静态调用。

谢谢。

你在做什么叫做切片 这是您获取派生类的对象并修剪掉父类中不存在的所有对象并将其分配给父类的地方。

你想要做的是使用 多态来做你解释的事情。 为此,请将向量从对象的副本更改为对象的 ptr。

如果对更多细节感兴趣,请使用提供的链接,其中包含的信息似乎非常完整。

快速修复是将您的As类更改为以下内容:

class As
{
public:
    void AddA( A &a ){ m_As.push_back( &a ); }
    void PrintXs()
    {
        for ( auto a : m_As )
        {
            a->printX();
        }
    }
private:
    std::vector<A*> m_As;
};

当你使用std::vector<A> m_As; ,向量只能适合A对象。 如果您改用指针,则多态可以工作并调用正确的printX函数。 但是,如果指向的对象的生命周期到期,则会出现悬空指针的问题。 为了解决这个问题,最好使用像std::unique_ptr这样的智能指针类。

由于您是按值传递对象,因此您无法利用多态性。 通过(智能)指针或引用传递它们。

 std::vector<std::shared_ptr<A>> m_As;

 // or 

 std::vector<std::unique_ptr<A>> m_As;

 // or 

 std::vector<A*> m_As; // be careful of bare pointers

 // or (since C++11)

 std::vector<std::reference_wrapper<A>> m_As;

std::reference_wrapper 魔法!

对于最后一个,您可以使用std::reference_wrapperstd::ref

class As
{
public:
    void AddA(A &a){ m_As.push_back( std::ref(a) ); }
    void PrintXs() const
    {
        for ( auto a : m_As )
        {
            a.get().printX();
        }
    }
private:
    std::vector<std::reference_wrapper<A>> m_As;
};

使用最后的代码,您不必更改main代码。

实时代码

for ( const auto & a : m_As )
{
        a.printX();
}

它会让你远离扩展副本并提供 B 实例而不是 A 实例,作为副本出现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM