通过指向base,static_cast,crtp,删除模板的指针派生的成员
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过指向base,static_cast,crtp,删除模板的指针派生的成员相关的知识,希望对你有一定的参考价值。
寻找:从指向base的指针访问派生类的成员。
反证法:
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>
我正在努力想出一个没有模板的解决方案。我知道的选项可行:
- void * //普通旧C并根据需要进行转换,它们都是机器中的指针(如内存地址)
static_cast<Derived*>(pointer_to_base);
//在编译时键入安全。- 将演员表包装在客户端的模板方法中(不要在这里与设计模式混淆)
最后一个选项似乎是最“优雅”的,即:
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);
}
};
承认,我怀疑几乎代表双倍的平衡(即使很长)是一个好主意(圆角,精度等问题)......
以上是关于通过指向base,static_cast,crtp,删除模板的指针派生的成员的主要内容,如果未能解决你的问题,请参考以下文章
使用static_cast进行父类指针转子类指针可能出现的问题
[C/C++]_[中级]_[static_cast的详细解析]