编辑:完全重述的问题:答案如下:
传递派生类型作为基类型的引用时遇到问题。似乎被引用的对象在从Derived转换为Base之前/之后清除/重新初始化了数据。
我认为当将Derived实例传递给一个将参数作为对Base对象(Derived - > Base&)的引用的函数时,引用的Base实例将在内存中与Derived对象保持一致,除非传递作为价值。
我有Base类,一种被认为是'只读'的数据状态:
class ReadonlyText
{
protected:
int m_Length;
char* m_String;
public:
ReadonlyText() m_Length(0), m_String(0) {} // a null base
ReadonlyText(const char* str) : m_Length(0), m_String(str)
{
do
{
m_Length++;
}while(*ptr++);
}
ReadonlyText(const ReadonlyText& copy) : m_Length(copy.m_Length), m_String(copy.m_String)
{
}
virtual ~Readonly() {};
... virtual nonsense
}; // lets not forget the semicolon
现在我有了Derived类,它是可写的:
class Text
{
public:
Text() : m_Length(1), m_String(Memory::New<char>(m_Length)) {}
Text(const ReadonlyText& copy) : m_Length(copy.m_Length), m_String(Memory::New<char>(m_Length))
{
for(whole i = 0; i < m_Length; ++i)
m_String[i] = copy.m_String[i];
}
Text(const Text& copy) : m_Length(copy.m_Length), m_String(Memory::New<char>(m_Length))
{
for(whole i = 0; i < m_Length; ++i)
m_String[i] = copy.m_String[i];
}
virtual ~Text()
{
if((m_Length != 0 && m_String != null<char>::value))
{
Memory::Delete<Char>(m_String);
m_Length = 0;
m_String = null<Char>::value;
}
}
// operator==(ReadonlyText&)
// operator!=(ReadonlyText&)
// operator==(Text&)
// operator!=(Text&)
// operator=(Text&)
// operator=(ReadonlyText&)
// I don't have time to format all these functions for best visibility in SO,
// I assure you that all these functions are implemented properly
// THE PROBLEM occurs in any function with ReadonlyText&, say:
Text operator+(const ReadonlyText& rhs)
{
//...
// Before the function begins, 'rhs.m_String' == 0x0
// see case below
}
};
// ...
int main(...)
{
Text t1 = Text("hello");
Text t2 = Text("world");
// in the debugger, at this point, both t1 && t2 '.m_String' is valid
// as "hello" and "world" respectively
// but when stepping into:
Text t3 = t1 + t2; // the function described above...
// ...which is t1.operator+(t2) // where t2 is passed as ReadonlyText&
// the debugger shows:
// t1.m_String == "hello"
// t2.m_String == 0x0 -- this should be "world"
// since no copy construction is occuring, (passing as reference), then
// the data should be consistent with the derived type, right?
}
在运算符+中,我尝试访问'rhs.m_String',它应该被评估为“world”,但由于某种原因已经被实例化为新的ReadonlyText而不是作为引用传递? / p>
此外,程序不会因任何消息而崩溃;没有分段错误或错误。相反,它只是完全退出,好像应用程序顺利运行直到主要结束?
没有比我在这里描述的更多了。 Memory :: New和Memory :: Delete封装内存操作(new和delete),以便New根据模板typename的大小和给定的长度返回一个指针。删除只是确保正确销毁指针。 null是一种结构,可确保类型名称的空值:
//class Memory:
template<typename T> static T* New(whole length = 1)
{
return (T*)(operator new (length * sizeof(T)));
}
template<typename T> static void Delete(T* pointer)
{
operator delete (pointer);
}
// null struct
template<typename T>
struct null
{
static constexpr T* value = 0x0;
}
真正的问题:
&LT; _&LT;在重新设计类层次结构时,我忘了删除派生成员(m_Length和m_String)。因此,Derived实例具有掩盖Base成员的成员。长话短说,当事情没有意义时,这可能是你的错:
class Base
{
...
protected:
int m_Length;
char* m_String;
};
class Derived : public virtual Base
{
...
protected: // xD WTH was I hoping to do here???
int m_Length;
char* m_String;
};
应该有一个用于继承的编译器功能来防止屏蔽,但在此之前要小心......要小心。感谢所有人帮助我和那些退出的人。
答案 0 :(得分:2)
如果这是您实际代码的一部分,那么我怀疑您的派生类中有错误,因为m_Data
属于您的Base
类,您无法直接在Derived
中初始化它1}}类,因为它是private
到Base
,所以你根本无法访问它,那么我假设你的m_Data
中还有一个成员Derived
,该成员隐藏了m_Data
的{{1}},因此您在调试器中看到的是Base
的{{1}},您在该函数中看到的是m_Data
Derived
m_Data
,因为它是使用Base
nullptr