Mixing abstract and template inheritance

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Israel

    Mixing abstract and template inheritance

    Can someone explain to me why I get a compiler error with the
    following code on the line obj.DoSomething ()?
    but if cast the object I get no error. The error I get is:
    Cannot access protected member
    'GenericDerived ClassTest.Base. DoSomething()' via a qualifier of type
    'GenericDerived ClassTest.Base' ; the qualifier must be of type
    'GenericDerived ClassTest.TBase <DerivedType> ' (or derived from it)

    Why does it believe the object has to derive from TBase<DerivedTy pe>?
    when all it needs to do is derive from Base since that's where the
    method is and that's also what TBase<DerivedTy pederives from.

    It seems to me that the compiler is confused because generics are kind
    of like templates/macros and maybe doesn't know how to really traverse
    the inheritance hierarchy in all cases?

    here's the code:
    /// <summary>
    /// Templated absract class
    /// </summary>
    /// <typeparam name="DerivedTy pe"></typeparam>
    public abstract class TBase<DerivedTy pe: Base
    where DerivedType : TBase<DerivedTy pe>, new()
    {
    public TBase()
    {
    }

    public static DerivedType StaticDoSomethi ng()
    {
    // Create a new derived class type
    Base obj = (Base)(new DerivedType());

    // Let the base class first do something to the object
    StaticDoSomethi ngImpl(ref obj);

    // Call the derived class
    #if true // This yields the error "Cannot access protected
    member..."
    obj.DoSomething ();
    #else // This works fine
    TBase<DerivedTy peobj2 = (TBase<DerivedT ype>)obj;
    obj2.DoSomethin g();
    #endif

    return (DerivedType)ob j;
    }
    }

    /// <summary>
    /// Abstract base class
    /// </summary>
    public abstract class Base
    {
    public Base()
    {
    }

    public static void StaticDoSomethi ngImpl(ref Base obj)
    {
    // Do something to obj
    }

    protected abstract void DoSomething();
    }
  • jmDesktop

    #2
    Re: Mixing abstract and template inheritance

    On Jun 12, 12:06 pm, Israel <israeldip...@h otmail.comwrote :
    Can someone explain to me why I get a compiler error with the
    following code on the line obj.DoSomething ()?
    but if cast the object I get no error.  The error I get is:
    Cannot access protected member
    'GenericDerived ClassTest.Base. DoSomething()' via a qualifier of type
    'GenericDerived ClassTest.Base' ; the qualifier must be of type
    'GenericDerived ClassTest.TBase <DerivedType> ' (or derived from it)
    >
    Why does it believe the object has to derive from TBase<DerivedTy pe>?
    when all it needs to do is derive from Base since that's where the
    method is and that's also what TBase<DerivedTy pederives from.
    >
    It seems to me that the compiler is confused because generics are kind
    of like templates/macros and maybe doesn't know how to really traverse
    the inheritance hierarchy in all cases?
    >
    here's the code:
    /// <summary>
    /// Templated absract class
    /// </summary>
    /// <typeparam name="DerivedTy pe"></typeparam>
    public abstract class TBase<DerivedTy pe: Base
        where DerivedType : TBase<DerivedTy pe>, new()
    {
        public TBase()
        {
        }
    >
        public static DerivedType StaticDoSomethi ng()
        {
            // Create a new derived class type
            Base obj = (Base)(new DerivedType());
    >
            // Let the base class first do something to the object
            StaticDoSomethi ngImpl(ref obj);
    >
            // Call the derived class
    #if true    // This yields the error "Cannot access protected
    member..."
            obj.DoSomething ();
    #else       // This works fine
            TBase<DerivedTy peobj2 = (TBase<DerivedT ype>)obj;
            obj2.DoSomethin g();
    #endif
    >
            return (DerivedType)ob j;
        }
    >
    }
    >
    /// <summary>
    /// Abstract base class
    /// </summary>
    public abstract class Base
    {
        public Base()
        {
        }
    >
        public static void StaticDoSomethi ngImpl(ref Base obj)
        {
            // Do something to obj
        }
    >
        protected abstract void DoSomething();
    >
    >
    >
    }- Hide quoted text -
    >
    - Show quoted text -
    Curious. Why do you have to cast to Base, if your DerivedType is a
    Base type? Why this:

    Base obj = (Base)(new DerivedType());

    Instead of

    Base obj = new DerivedType();

    Sorry. I know that's not what you asked. I am learning, trying to
    understand.

    Comment

    • Jon Skeet [C# MVP]

      #3
      Re: Mixing abstract and template inheritance

      On Jun 12, 5:06 pm, Israel <israeldip...@h otmail.comwrote :
      Can someone explain to me why I get a compiler error with the
      following code on the line obj.DoSomething ()?
      It's worth getting rid of generics from the equation to start with -
      they're irrelevant here. Likewise you don't need to have any abstract
      classes. The issue is to do with your understanding of the "protected"
      access modifier. Here's a simpler example:

      class Base
      {
      protected void Foo() { }
      }

      class Derived : Base
      {
      public void CallFoo(Base b)
      {
      b.Foo();
      }
      }

      class Other : Base {}

      You'll see the same error message. "protected" doesn't mean "can be
      called by any derived type on any instance of the base class". It
      means "can be called by any derived type on any instance *of the same
      type* (including instances of further derived types)".

      So Derived can call Foo on any Derived, but not on an instance of
      "Other".

      The C# 3.0 language spec describes it like this in section 3.5.3:
      <quote>
      When a protected instance member is accessed outside the program text
      of the class in which it is declared, and when a protected internal
      instance member is accessed outside the program text of the program in
      which it is declared, the access must take place within a class
      declaration that derives from the class in which it is declared.
      Furthermore, the access is required to take place through an instance
      of that derived class type or a class type constructed from it. This
      restriction prevents one derived class from accessing protected
      members of other derived classes, even when the members are inherited
      from the same base class.
      </quote>

      Jon

      Comment

      • Israel

        #4
        Re: Mixing abstract and template inheritance

        On Jun 12, 12:55 pm, "Jon Skeet [C# MVP]" <sk...@pobox.co mwrote:
        <quote>
        When a protected instance member is accessed outside the program text
        of the class in which it is declared, and when a protected internal
        instance member is accessed outside the program text of the program in
        which it is declared, the access must take place within a class
        declaration that derives from the class in which it is declared.
        Furthermore, the access is required to take place through an instance
        of that derived class type or a class type constructed from it. This
        restriction prevents one derived class from accessing protected
        members of other derived classes, even when the members are inherited
        from the same base class.
        </quote>
        Ok, that makes sense from the example you gave since it's impossible
        for the compiler to know whether the passed in object is the base
        class from another inheritance branch but you could argue that the
        compiler should know this to be impossible in my case since the
        creation of the object is within the method and that object is defined
        to be derived from the current class that it's in.
        Don't get me wrong it's not worth arguing too much because I could
        have just kept the original object as a DerivedType type and then
        everything would work fine.




        Comment

        • Jon Skeet [C# MVP]

          #5
          Re: Mixing abstract and template inheritance

          Israel <israeldiperi@h otmail.comwrote :
          <quote>
          When a protected instance member is accessed outside the program text
          of the class in which it is declared, and when a protected internal
          instance member is accessed outside the program text of the program in
          which it is declared, the access must take place within a class
          declaration that derives from the class in which it is declared.
          Furthermore, the access is required to take place through an instance
          of that derived class type or a class type constructed from it. This
          restriction prevents one derived class from accessing protected
          members of other derived classes, even when the members are inherited
          from the same base class.
          </quote>
          >
          Ok, that makes sense from the example you gave since it's impossible
          for the compiler to know whether the passed in object is the base
          class from another inheritance branch but you could argue that the
          compiler should know this to be impossible in my case since the
          creation of the object is within the method and that object is defined
          to be derived from the current class that it's in.
          You don't want the compiler to start having to make that kind of
          inference though - the complexity of the language balloons massively.
          Heck, type inference in C# 3 is complicated enough as it is for a
          single expression - I don't want to have to wade through rules about
          what extra information the compiler is required to take into account.
          It would get really hairy.
          Don't get me wrong it's not worth arguing too much because I could
          have just kept the original object as a DerivedType type and then
          everything would work fine.
          Exactly. And in cases where you know better than the compiler for
          whatever reason, you can always cast. That's what casting's for :)

          --
          Jon Skeet - <skeet@pobox.co m>
          Web site: http://www.pobox.com/~skeet
          Blog: http://www.msmvps.com/jon.skeet
          C# in Depth: http://csharpindepth.com

          Comment

          Working...