以下是一个简单(但可编译)的示例,说明了可能的切片赋值场景。
#include <string>
struct Base
{
// Mutating method. Not a chance of making it virtual.
template <typename Anything>
Base& operator=(const Anything& x)
{
m_int = x.AsInteger();
return *this;
}
int AsInteger() const
{
return m_int;
}
int m_int;
};
struct Derived : public Base
{
template <typename Anything>
Derived& operator=(const Anything& x)
{
m_text = x.AsString();
Base::operator=(x);
return *this;
}
const std::string& AsString() const
{
return m_text;
}
// Invariant: Derived::m_text matches Base::m_x.
std::string m_text;
};
void ExamineBase(const Base* b)
{
b->AsInteger();
}
void ExamineBase(const Base& b)
{
b.AsInteger();
}
void InitBase(Base* b)
{
*b = Base();
}
void InitBase(Base& b)
{
b = Base();
}
int main()
{
Base b;
InitBase(b); // <----- (1)
InitBase(&b); // <----- (2)
Derived d;
Derived& ref = d;
Derived* ptr = &d;
ExamineBase(ref); // <----- (3)
ExamineBase(ptr); // <----- (4)
InitBase(ref); // <----- (5)
InitBase(ptr); // <----- (6)
return 0;
}
第1行、第2行、第3行和第4行是好的。
第5行和第6行存在问题:它们只更改完整对象中的基础子对象,显然破坏了 Base::m_int 和 Derived::m_text 之间的一致性。
我有兴趣防止这种切片修改发生,同时保留第1行、第2行、第3行和第4行的有效性。
因此,问题是:
a)有没有什么技巧可以防止通过指向派生类的指针调用基类的非const成员函数?
b)有没有什么技巧可以阻止从Derived *到Base *的标准隐式转换,但仍允许从Derived *到const Base *的转换?
Base
应该是Derived
的成员。 - user4442671Base
足够的地方使用Derived
。为了给你个形象化印象,我们可以想象Base
是一个类似std::span
的非拥有访问器,而Derived
则是一组拥有容器中的某个类。 - Igor G