派生的成员 通过指向基、static_cast、crtp、删除模板的指针
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 的指针访问派生的成员,即:
Base* foo = new Derived();
foo->member_of_derived; // no go
因此,我正在使用:
Client<Base>
Client<Derived>
我正在尝试提出一个无需模板即可使用的解决方案。我知道的选项会起作用:
- void*//普通的旧 C 和必要的强制转换,它们都是指针 (如内存地址(在机器中
static_cast<Derived*>(pointer_to_base);
//type 在编译时是安全的。- 将强制转换包装在客户端的模板方法中(此处不要与设计模式混淆(
最后一个选项似乎是最"优雅"的,即:
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 的指针,这反过来又会让我访问它们各自的成员。
虚拟 getter 可以为您解决问题; 由于数据类型不同,您可以将它们打包到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);
}
};
承认,我怀疑几乎以双倍(即使长(表示平衡是一个好主意(四舍五入、精度等问题(......
- 如何理解C++标准N3337中的expr.const.cast子句8
- C++Cast运算符过载
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- CRTP 单一实例不完整类型或非文本类型
- CRTP 中的复制赋值运算符 - gcc vs clang 和 msvc
- 将具有固定签名的自定义函数名称注入 CRTP
- 如何在MISRA C++之后实施CRTP
- 检测使用 CRTP 的类中的成员函数
- 简化使用 CRTP 模式的类的声明
- C++ CRTP initialization
- 概念可以与 CRTP 习语一起使用吗?
- CRTP - 危险的内存访问?
- 如何断言 CRTP 的函数为最终函数?
- CRTP 模式不会触发完整的模板实例化
- 在 CRTP 中使用嵌套名称说明符
- CRTP 与基类向量
- 派生的成员 通过指向基、static_cast、crtp、删除模板的指针
- 为什么 CRTP 模板C++给出无效参数错误?
- 错误:"cast"未命名类型void setCastDescription(std::string
- CRTP相对于抽象类的优势