Make your own free website on Tripod.com

MKoD - D Programming Language

Class Inheritance Issue in D

Caution, you may Slip 'n' Fall! D Class Inheritance Issue:

The non-working example below is some modified code found on a D.Bugs forum posted as a problem with inherting functions (private, protected, or public...it really didn't matter) from the Base / SuperClass within the newly Derived Class. As it turns out, when the function-name (return-type, parameter-types, number of parameters didn't matter) is shared between the Base Class and the SubClass... the Base Class functions of that name become hidden / unreachable to the SubClass.

// class_inhert_prm.d
private import std.stdio;

class A 
{
    void test() { writefln( "A.test() Called."); }
    void test( in int iVal ) { writefln( "A.test( in int iVal=\"%s\" ) Called.", iVal ); }

    void test2( in int iVal ) { writefln( "A.test2( in int iVal=\"%s\" ) Called.", iVal ); }
}

class B : A
{
    void test() { writefln( "B.test() Called."); }
}

int main( in char[][] args )
{
    B ob = new B();
    
    ob.test( 6 );  // <--A.test( in int iVal ) should be called here.
    ob.test2( 7 ); // if above error is commented out, A.test2( in int iVal ) works.
    ob.test();

    return 0;

} // end int main( in char[][] )
C:\dmd\MKOD_ex>..\bin\dmd class_inhert_prm.d
class_inhert_prm.d(20): function class_inhert_prm.B.test () does not match argument types (int)
class_inhert_prm.d(20): Error: expected 0 arguments, not 1

C:\dmd\MKOD_ex>

One of the best ways around this issue, was to add an "alias" in the SubClass that will pull in all the shared function-names into the same namespace for function overloading to work correctly.

Below look for alias A.test() test;

// class_inhert2.d - last tested with D v1.0
/+
 ' When Inherting Base Class functions that have the function same name
 ' has the Base Class function causes them to remain hidden / uncallable.
 +/
private import std.stdio;

class A 
{
    void test() { writefln( "A.test() Called."); }
    void test( in int iVal ) { writefln( "A.test( in int iVal=\"%s\" ) Called.", iVal ); }

    void test2( in int iVal ) { writefln( "A.test2( in int iVal=\"%s\" ) Called.", iVal ); }
}

class B : A
{
    /+ 
     ' An alias brings in all the same function-name
     ' (note: that it doesn't matter about the function's 
     ' return-type or types of paramters nor the number of 
     ' parameters) into Class B's namespace.
     +/ 
    alias A.test test;
    void test() { writefln( "B.test() Called."); }

    // Could call B.test() 1st then call A.test() in this case.
    //void test() { writefln( "B.test() Called."); super.test(); }
}

int main( in char[][] args )
{
    B ob = new B();
    
    ob.test( 6 );
    ob.test2( 7 );
    ob.test();

    return 0;

} // end int main( in char[][] )
C:\dmd\MKOD_ex>dmd class_inhert2.d
C:\dmd\bin\..\..\dm\bin\link.exe class_inhert2,,,user32+kernel32/noi;

C:\dmd\MKOD_ex>class_inhert2
A.test( in int iVal="6" ) Called.
A.test2( in int iVal="7" ) Called.
B.test() Called.

C:\dmd\MKOD_ex>

Another way to pull in the SuperClass shared function-names into the SubClass' namespace was to use an "interface" to map them in. This of course will force the SuperClass to have all the shared versions of the function-names that will be used plus with their correct return-types, parameters, and number of parameters. But there may be cases where this type of side-effect may allow some different type of functionally...it's always good to have options. You decide.

// class_inhert3.d
/+
 ' When Inherting Base Class functions that have the function same name
 ' has the Base Class function causes them to remain hidden / uncallable.
 +/
private import std.stdio;

/+
 ' Using an interface that has all the [return] function( [parameter(s)] ) 
 ' that'll be shared between the SuperClass (Base) and the SubClass(es) which 
 ' will make up the Derived Class' namespace, will make function overloading 
 ' to work correctly.
 +/ 
interface I
{
    void test();
    void test( in int );
}

class A : I
{
    void test() { writefln( "A.test() Called."); }
    void test( in int iVal ) { writefln( "A.test( in int iVal=\"%s\" ) Called.", iVal ); }

    void test2( in int iVal ) { writefln( "A.test2( in int iVal=\"%s\" ) Called.", iVal ); }
}

class B : A
{
    void test() { writefln( "B.test() Called."); }
}

int main( in char[][] args )
{
    B ob = new B();
    
    ob.test2( 7 );

    // Interfaces can be inherited and functions overridden
    I oib = cast(I) ob;
    oib.test( 6 );
    oib.test();

    return 0;

} // end int main( in char[][] )
C:\dmd\MKOD_ex>..\bin\dmd class_inhert3.d
C:\dmd\bin\..\..\dm\bin\link.exe class_inhert3,,,user32+kernel32/noi;

C:\dmd\MKOD_ex>class_inhert3
A.test2( in int iVal="7" ) Called.
A.test( in int iVal="6" ) Called.
B.test() Called.

C:\dmd\MKOD_ex>
Mars: fourth Rock from the Sun.