C++ CRTP 派生类对象切片
C++ CRTP derived class object slicing
我有基类帐户和派生类学生和老师。我在 CRTP 中实现读/写,这样我就不需要在每个类中编写函数。
奇怪的是,读取函数中有对象切片,*这在函数中使用,但在写入函数中没有。
谁能解释一下这里发生了什么?以及如何解决它?
// Account.h
class Account {
public:
Account();
virtual void callMenu() = 0;
protected:
int ID;
// Some more data (Total of 148 bytes)
}
// AccountCRTP.h
template<class T>
class AccountCRTP : public Account {
public:
// To prevent object slicing
void callMenu() {
T account;
account.ID = this->ID;
cout << "Account size: " << sizeof(account) << " bytesn"; pause(); // 268 bytes
if (account.readData())
account.menu();
}
bool readData() {
T account;
cout << "Account size : " << sizeof(account) << " bytesn"; pause(); // 268 bytes
cout << "This size : " << sizeof(*this) << " bytesn"; pause(); // 148 bytes??? Why?
while (reading data to account) {
if (this->ID == account.ID) {
*this = account; // Object slicing happens
return true;
}
}
return false;
}
bool writeData() {
T temp;
int position = 0l
while (reading data to temp) {
if (this->ID == account.ID)
break;
position++;
}
cout << "Account size : " << sizeof(temp) << " bytesn"; pause(); // 268 bytes
cout << "This size : " << sizeof(*this) << " bytesn"; pause(); // 148 bytes right?
datafile.seekp(position * sizeof(T));
// For unknown reason this also writes scores of the student
// Object slicing didn't happen here. Why?
datafile.write((char*)this, sizeof(T));
}
private:
// No additional data in this class (Still 148 bytes)
}
// Student.h
class Student :
public AccountCRTP<Student>
{
public:
void menu() {
// Student menu
}
private:
// Some more 120 bytes of data (Total of 268 bytes)
}
// main.cpp
int main() {
vector<unique_ptr<Account>> account;
account.push_back(unique_ptr<Account>(new Student));
account.push_back(unique_ptr<Account>(new Teacher));
account[0]->callMenu();
}
*this = account; // Object slicing happens
"发生对象切片">是的,并且您正在丢失account
的任何特定属性(成员变量(
你真正需要的是
*static_cast<T*>(this) = account;
保留派生T
中的东西.
static_cast<T*>(this)
诀窍是类型安全的全部意义,以使静态多态性工作。
所有可能的类型检查都将在编译时应用。
让我们在这个问题上多一点语法糖,就像@Yakk的评论中提到的那样:
template<typename T>
struct CRTPBase {
T const& self() const { return *static_cast<T const*>(this); }
T& self() { return *static_cast<T*>(this); }
};
然后这条线变成
self() = account;
对于这种情况,即使使用 c 预处理器宏似乎也是合适的:
#define DEFINE_CRTP_SELF(derived_param)
derived_param const& self() const { return *static_cast<derived_param const*>(this); }
derived_param& self() { return *static_cast<derived_param*>(this); }
并像这样使用它:
template<typename T>
class CRTP {
public:
DEFINE_CRTP_SELF(T);
};
注意:如果你在运行时有一些奇怪的东西(来自void*
指针左右(,你就迷失在地狱里了。
相关文章:
- 避免矢量中的对象切片<Base><shared_ptr>
- 专门化模板覆盖函数/避免对象切片
- C++ 被此代码与多态性、指针和对象切片混淆
- 我们能胜过对象切片吗?
- 如何在考虑对象切片的同时通过传入单个 Base 对象来打印出数组中的对象?
- 成员变量和对象切片
- 如何在不引入未来对象切片的情况下实现 ICloneable
- 避免对象切片
- 故意对对象切片是一种可行的技术吗?
- 对象切片:通过按值派生为 Base - 安全还是危险?
- C++ CRTP 派生类对象切片
- C++ - 即使在使用指针后也能进行对象切片
- 了解对象切片
- 使用对象切片可靠地从多个基类之一中复制
- 对象切片和隐式类型转换
- 一种克服对象切片的方法
- 按引用传递可避免对象切片
- 使用CRTP时的对象切片
- 对象切片:从基类对象访问分层的类方法
- 这会导致对象切片吗?