[英]C++ CRTP derived class object slicing
I have base class Account and derived class Student and Teacher.我有基类 Account 和派生类 Student 和 Teacher。 I implement read/write in the CRTP so that I dont need to write the function in each class.我在 CRTP 中实现了读/写,这样我就不需要在每个类中编写函数。
Strangely there is object slicing in the read function and *this used in the function, but not in the write function.奇怪的是,read函数中有对象切片,函数中使用了*this,而write函数中没有。
Can anyone explain what's happening here?谁能解释这里发生了什么? And how to fix it?以及如何修复它?
// 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) << " bytes\n"; pause(); // 268 bytes
if (account.readData())
account.menu();
}
bool readData() {
T account;
cout << "Account size : " << sizeof(account) << " bytes\n"; pause(); // 268 bytes
cout << "This size : " << sizeof(*this) << " bytes\n"; 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) << " bytes\n"; pause(); // 268 bytes
cout << "This size : " << sizeof(*this) << " bytes\n"; 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
"Object slicing happens" Yes, and you're loosing any specific properties (member variables) of account
“对象切片发生”是的,您正在丢失account
任何特定属性(成员变量)
What you actually need is你真正需要的是
*static_cast<T*>(this) = account;
to preserve the stuff from the derived T
.保留派生T
。
The static_cast<T*>(this)
trick is the whole point of type safety to make Static Polymorphism work. static_cast<T*>(this)
技巧是使静态多态起作用的类型安全的全部要点。
All possible type checks will be applied at compile time.所有可能的类型检查都将在编译时应用。
Let's stray a bit more syntactic sugar on this like mentioned from @Yakk's comment :让我们在@Yakk 的评论中提到的更多语法糖:
template<typename T>
struct CRTPBase {
T const& self() const { return *static_cast<T const*>(this); }
T& self() { return *static_cast<T*>(this); }
};
Then the line becomes然后线变成
self() = account;
For such case even using a c-preprocessor macro seems to be appropriate:对于这种情况,即使使用 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); }
And use it like:并像这样使用它:
template<typename T>
class CRTP {
public:
DEFINE_CRTP_SELF(T);
};
Note: If you have something weird at runtime (coming from void*
pointers or so), you're lost in hell.注意:如果你在运行时有一些奇怪的东西(来自void*
指针左右),你就会迷失在地狱中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.