如何在函数内将指针从基数更改为派生 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*
永远是噩梦!
我想创建某种工厂函数,但我不想返回指向某个 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*
永远是噩梦!