![](/img/trans.png)
[英]When is a `static_cast<Base*>(static_cast<void*>(derived))` from a pointer to a derived class valid?
[英]Member of derived by pointer to base, static_cast, crtp, removing templates
寻找:从指向基址的指针访问派生类的成员。
荒谬的还原:
class Base
{
public:
int member_of_base;
};
class Derived : public Base
{
public:
int member_of_derived;
};
我目前正在使用模板:
template <class T>
class Client
{
T* data; // T is Base or Derived
};
类层次结构中的构成层次很少,因此我必须在所有层次结构中携带模板类型参数。 克服此问题的最佳方法是什么? 显然,我无法通过指向Base的指针来访问Derived的成员,即:
Base* foo = new Derived();
foo->member_of_derived; // no go
因此,我正在使用:
Client<Base>
Client<Derived>
我正在尝试提出一种无需模板即可使用的解决方案。 我知道可以使用的选项:
static_cast<Derived*>(pointer_to_base);
//在编译时输入safe。 最后一个选项似乎是最“优雅”的,即:
template <class T>
T* get_data() const { return static_cast<T*>(data); }
但是,四处看看告诉我可能存在一种未知的方法。 我看到了CRTP,但是这使我回到了模板,这是我想要的原始东西。 实现此目标的方法或流行方法是什么?
实际的代码将shared_ptr,weak_ptr和enable_shared_from_this与weak_from_this一起使用。 我正在寻找类型安全的“多态成员”访问权限。
编辑:他们不只是“整数”。 它们可以是完全不同的类型,例如base中的protobuf和派生中的Json :: Value。 而且我正在尝试使用指向Base / Derived的指针,这将使我能够访问它们各自的成员。
虚拟吸气剂可以为您解决问题; 由于数据类型不同,您可以将它们打包到std::variant
。
class Base
{
// having private members probably is more appropriate
int member_of_base;
public:
using Data = std::variant<int, double>;
virtual ~Base() { } // virtual functions -> have a virtual destructor!
virtual Data getMember() // or just "member", if you prefer without prefix
{
return member_of_base;
}
};
class Derived : public Base
{
double member_of_derived;
public:
Data getMember() override
{
return member_of_derived;
}
};
std::unique_ptr<Base> foo = new Base();
foo->getMember(); // member_of_base;
std::unique_ptr<Base> bar = new Derived();
bar->getMember(); // member_of_derived;
承认,不是完全没有模板, std::variant
是一个,但是我想以这种形式可以接受...
但是存在一些问题:
visit
函数。 如果可以将要完成的工作委托给类本身,则可以解决所有这些问题:
class Base
{
int member_of_base;
public:
virtual ~Base() { }
virtual void doSomething()
{
/* use member_of_base */
}
};
class Derived : public Base
{
double member_of_derived;
public:
void doSomething() override
{
/* use member_of_derived */
}
};
后者将是真正的多态方法,通常是可行的方法。 而上面的示例返回的是void,您可能只需要在基类和派生类中进行所有必要的计算,直到最终获得某种通用数据类型并返回该类型。 例:
class Base
{
int64_t m_balance; // in 100th of currency in use
public:
virtual ~Base() { }
virtual int64_t balance()
{
return m_balance;
}
};
class Derived : public Base
{
long double m_balance; // arbitrary values in whole currency entities
public:
int64_t balance() override
{
// calculate 100th of currency, correctly rounded:
return std::llround(m_balance * 100);
}
};
诚然,我怀疑以双倍(即使很长)表示平衡是一个好主意(带有四舍五入,精度等问题)...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.