1

编辑:完全重述的问题:回答如下:

将派生类型作为对基类型的引用传递时遇到问题。似乎引用的对象在从 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?

}

发生的情况是,在 operator+ 中,我尝试访问“rhs.m_String”,它应该被评估为“world”,但由于某种原因已被实例化为新的 ReadonlyText 而不是作为参考传递?

此外,该程序不会因任何消息而崩溃;没有分段错误或错误。相反,它只是完全退出,好像应用程序运行顺利,直到 main 结束?

没有比我在这里描述的更多的事情发生了。Memory::New 和 Memory::Delete 封装了内存操作(new 和 delete),以便 New 根据模板类型名的大小和给定的长度返回一个指针。删除只是确保正确销毁指针。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;
}

真正的问题:

<_< 在重新设计类层次结构时,我忘记删除派生成员(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;
};

应该有一个用于继承的编译器功能可以防止屏蔽,但在此之前要小心……只是要小心。感谢所有尝试帮助我的人,以及那些退出的人。

4

1 回答 1

2

如果这是您实际代码的一部分,那么我怀疑您的派生类中有错误,因为m_Data属于您的Base类,您不能直接在您的Derived类中初始化它,并且因为它是privateBase根本无法访问它,那么我假设您的成员中也有一个成员m_DataDerived并且该成员隐藏了m_Dataof Base,因此您在调试器中看到的是m_Dataof ,Derived而您在函数中看到的是m_Datathat Basenullptr因为它是使用默认构造函数初始化的Base

于 2012-10-18T21:55:14.810 回答