[英]Member of derived by pointer to base, static_cast, crtp, removing templates
Looking for: accessing member of a derived class from a pointer to base. 寻找:从指向基址的指针访问派生类的成员。
Reductio ad absurdum: 荒谬的还原:
class Base
{
public:
int member_of_base;
};
class Derived : public Base
{
public:
int member_of_derived;
};
I'm currently using templates: 我目前正在使用模板:
template <class T>
class Client
{
T* data; // T is Base or Derived
};
There are few levels of composition in the class hierarchy, so I have to carry the template type parameter through all of the hierarchy. 类层次结构中的构成层次很少,因此我必须在所有层次结构中携带模板类型参数。 What is the best approach to overcome this?
克服此问题的最佳方法是什么? Obviously I cannot access the member of Derived via a pointer to Base, ie:
显然,我无法通过指向Base的指针来访问Derived的成员,即:
Base* foo = new Derived();
foo->member_of_derived; // no go
Thus, I'm using: 因此,我正在使用:
Client<Base>
Client<Derived>
I'm trying to come up with a solution that works without the templates. 我正在尝试提出一种无需模板即可使用的解决方案。 Options that I know would work:
我知道可以使用的选项:
static_cast<Derived*>(pointer_to_base);
//type safe at compile time. The last option seems to be the most "elegant", ie: 最后一个选项似乎是最“优雅”的,即:
template <class T>
T* get_data() const { return static_cast<T*>(data); }
However, looking here and there tells me there might exist a way unknown to me. 但是,四处看看告诉我可能存在一种未知的方法。 I saw CRTP, but that brings me back to templates, which is the original thing I want to go without.
我看到了CRTP,但是这使我回到了模板,这是我想要的原始东西。 What are the ways, or popular approaches, to achieve such a goal?
实现此目标的方法或流行方法是什么?
The real code uses shared_ptr, weak_ptr and enable_shared_from_this with weak_from_this. 实际的代码将shared_ptr,weak_ptr和enable_shared_from_this与weak_from_this一起使用。 I'm looking for a type safe "polymorphic member" access.
我正在寻找类型安全的“多态成员”访问权限。
EDIT: they're not just "ints". 编辑:他们不只是“整数”。 They can be totally different types, as in protobuf in base and Json::Value in derived.
它们可以是完全不同的类型,例如base中的protobuf和派生中的Json :: Value。 And I'm trying to use the pointers to Base/Derived, which in turn would give me access to their respective members.
而且我正在尝试使用指向Base / Derived的指针,这将使我能够访问它们各自的成员。
A virtual getter can solve the issue for you; 虚拟吸气剂可以为您解决问题; as data types differ, you might pack them into a
std::variant
. 由于数据类型不同,您可以将它们打包到
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;
Admitted, not yet totally without templates, std::variant
is one, but I suppose in that form it is acceptable... 承认,不是完全没有模板,
std::variant
是一个,但是我想以这种形式可以接受...
There are some issues with, though: 但是存在一些问题:
visit
function for. visit
函数。 If you can delegate the work to be done to the classes themselves, you get around all these problems: 如果可以将要完成的工作委托给类本身,则可以解决所有这些问题:
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 */
}
};
The latter would be the true polymorphic approach and normally the way to go; 后者将是真正的多态方法,通常是可行的方法。 whereas the sample above returns void, you might just do all the calculations necessary in base and derived classes until you finally get to some common data type and return this one.
而上面的示例返回的是void,您可能只需要在基类和派生类中进行所有必要的计算,直到最终获得某种通用数据类型并返回该类型。 Example:
例:
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);
}
};
Admitted, I doubt pretty much representing a balance in double (even if long) is a good idea (issues with rounding, precision, etc)... 诚然,我怀疑以双倍(即使很长)表示平衡是一个好主意(带有四舍五入,精度等问题)...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.