如何在函数内将指针从基数更改为派生 class

How to change pointer from base to derived class inside a function

我想创建某种工厂函数,但我不想返回指向某个 class 对象的指针,而是想将指向基 class 的指针传递给函数作为论据。更麻烦的是,该函数接受void指针。

这是我试过的代码。

#include <iostream>
#include <string>

class Base {
    public:
    std::string isA()
    {
        return "Base";
    }
};

class Derived : public Base {
    public:
    std::string isA()
    {
        return "Derived";
    }
};


void func(void* obj)
{
    Derived* derived_ptr = (Derived*)obj;
    std::cout << "Address of derived_ptr " << derived_ptr << "\n";
    std::cout << "From func " << derived_ptr->isA() << "\n";

}

int main()
{
  Base* instance;
  func(instance);
  std::cout << "Address of instance " << instance << "\n";
  std::cout << "From main " << instance->isA() << "\n";
}

输出:

Address of derived_ptr 0x4009b0                                                                                                               
From func Derived                                                                                                                             
Address of instance 0x4009b0                                                                                                                  
From main Base   

从输出中可以明显看出地址是相同的,但在每种情况下都是不同的对象(Base 和 Derived. 有没有办法让它以这种形式工作?

TLDR:使用 static_cast.

void func(void* obj)
{
    auto derived_ptr = static_cast<Derived*>(obj);
}

如果你想要动态多态性,你的代码应该是这样的。但是对 isA 的函数调用的结果将是相同的,因为您创建了一个 Derived 对象。您可以使用带有检查的 dynamic_cast 来调用仅存在于派生 class.

中的方法

更新:我也添加了一个 void* 实现。

#include <iostream>
#include <string>
#include <memory>

class Base {
    public:
    virtual ~Base() = default;
    virtual std::string isA()
    {
        return "Base";
    }
};

class Derived : public Base {
    public:
    virtual std::string isA() override
    {
        return "Derived";
    }
    void derivedMethod() {
        std::cout << "I am a derived only method\n";
    }
};

void func2(Base* obj)
{
    if (auto derived_ptr = dynamic_cast<Derived*>(obj)) {
        derived_ptr->derivedMethod();
        std::cout << "Address of derived_ptr " << derived_ptr << '\n';
        std::cout << "From func " << derived_ptr->isA() << '\n';
    }
}

void func(void* obj)
{
    auto derived_ptr = static_cast<Derived*>(obj); 
    derived_ptr->derivedMethod();
    std::cout << "Address of derived_ptr " << derived_ptr << '\n';
    std::cout << "From func " << derived_ptr->isA() << '\n';
}

int main()
{
    //Base* instance = new Derived();
    std::unique_ptr<Base> instance = std::make_unique<Derived>();
    func(instance.get());
    std::cout << "Address of instance " << instance << '\n';
    std::cout << "From main " << instance->isA() << '\n';
    //delete instance;
}

如果您不想通过 virtual 函数实现 运行 时间多态性,您可以使用 std::variant 代替。这使您能够在没有公共基础 class 的情况下使用不相关的对象,它不需要启用 RTTI,这意味着它也适用于小型嵌入式系统并且它仍然是类型安全的,因为 std::variant 保留了对象的信息当前存储在 variant 变量中。

您也可以根据需要将此类变体存储在容器中。如果将 std::variant 与指针类型一起使用,使用这种联合的潜在浪费只是额外的指针实例。

但是,是的,它通过使用指针有另一个间接寻址,但在您的示例中,您也有一个 void* 和像强制转换一样的检查和转换的“一些想法”。

class Base {
    public:
        std::string isA()
        {
            return "Base";
        }
};

class Derived : public Base {
    public:
        std::string isA()
        {
            return "Derived";
        }
};

class Another
{
    public:
        std::string isA() { return "Another"; }
};

using VAR_T = std::variant< std::unique_ptr<Base>, std::unique_ptr<Derived>, std::unique_ptr<Another> >;

VAR_T Factory( int what )
{
    switch ( what )
    {   
        case 0: return VAR_T{std::make_unique<Base>()}; 
        case 1: return VAR_T{std::make_unique<Derived>()}; 
        case 2: return VAR_T{std::make_unique<Another>()}; 
    }   

    return {}; 
}

/* Never do such thing in real world code!!!!!!!!!!!!!!!!! */

void func(void* obj)
{
    VAR_T* var = reinterpret_cast< VAR_T* >( obj );
    std::string s = std::visit( []( auto& ptr ){ return ptr->isA(); }, *var);
    std::cout << "From func " << s << "\n";
}



int main()
{
    std::vector< VAR_T > vars;

    for ( int i = 0; i<3; i++)
    {   
        vars.push_back( Factory( i )); 
    }   

    for ( auto& var: vars )
    {   
        std::visit( []( auto& ptr ){ std::cout << ptr->isA() << std::endl; }, var );
    }   

    // and now via void*, but never use this in production code. DANGEROUS, NOT TYPE SAFE, 
    for ( auto& var: vars )
    {   
        func( &var );
    }  

}

编辑:添加了使用 void* 的代码,但这真的不应该成为任何生产系统的一部分! void* 永远是噩梦!