Note that there are some explanatory texts on larger screens.

plurals
  1. POSlicing: When passing derived as reference to base, the base references loses data?
    text
    copied!<p>EDIT: Completely restated question: Answer below:</p> <p>I am having problems when passing a derived type as a reference to the base type. It seems that the referenced object has it's data cleared/reinitialized before/after being casted from Derived to Base.</p> <p>I thought that when passing a Derived instance to a function that acccepts the parameter as a reference to the Base object (Derived -> Base&amp;), the referenced Base instance will stay consistent in memory to the Derived object, unless passed as value. </p> <p>I have the Base class, a state of data that is considered 'read-only':</p> <pre><code>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&amp; copy) : m_Length(copy.m_Length), m_String(copy.m_String) { } virtual ~Readonly() {}; ... virtual nonsense }; // lets not forget the semicolon </code></pre> <p>Now I have the Derived class, that is writable:</p> <pre><code>class Text { public: Text() : m_Length(1), m_String(Memory::New&lt;char&gt;(m_Length)) {} Text(const ReadonlyText&amp; copy) : m_Length(copy.m_Length), m_String(Memory::New&lt;char&gt;(m_Length)) { for(whole i = 0; i &lt; m_Length; ++i) m_String[i] = copy.m_String[i]; } Text(const Text&amp; copy) : m_Length(copy.m_Length), m_String(Memory::New&lt;char&gt;(m_Length)) { for(whole i = 0; i &lt; m_Length; ++i) m_String[i] = copy.m_String[i]; } virtual ~Text() { if((m_Length != 0 &amp;&amp; m_String != null&lt;char&gt;::value)) { Memory::Delete&lt;Char&gt;(m_String); m_Length = 0; m_String = null&lt;Char&gt;::value; } } // operator==(ReadonlyText&amp;) // operator!=(ReadonlyText&amp;) // operator==(Text&amp;) // operator!=(Text&amp;) // operator=(Text&amp;) // operator=(ReadonlyText&amp;) // 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&amp;, say: Text operator+(const ReadonlyText&amp; 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 &amp;&amp; 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&amp; // 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? } </code></pre> <p>What happens is, in operator+, I attempt to access 'rhs.m_String', which should be evaluated to "world", but for some reason has been instanced as a new ReadonlyText instead of being passed as a reference??</p> <p>Further, the program does not crash with any messages; no segmentation fault or error. Instead, it just completely quits, as if the application ran smoothly until end of main?</p> <p>There isn't much more going on than what I describe here. Memory::New and Memory::Delete encapsulate memory operations (new and delete) so that New returns a pointer based on the size of the template typename and the given length. Delete just ensures that proper destruction of the pointers. And null is a structure that ensures consitent null values for typenames:</p> <pre><code>//class Memory: template&lt;typename T&gt; static T* New(whole length = 1) { return (T*)(operator new (length * sizeof(T))); } template&lt;typename T&gt; static void Delete(T* pointer) { operator delete (pointer); } // null struct template&lt;typename T&gt; struct null { static constexpr T* value = 0x0; } </code></pre> <p>THE REAL PROBLEM:</p> <p>&lt;_&lt; I forgot to remove the Derived members (which are m_Length and m_String) when redesigning the class hierarchy. So the Derived instance had members that were masking the Base members. Long story short, when something doesn't make sense, it's probably your fault:</p> <pre><code>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; }; </code></pre> <p>There should be a compiler feature for inheritance that prevents masking, but until then be careful...just be careful. Thanks all to tried helping me, and for those who backed out.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload