Why can not I access a field but the method succeeds?

4

I have the following code in C #:

namespace ConsoleApplication4
{
    public class BaseClass
    {
        public BaseClass()
        {
            System.Console.WriteLine("BaseClass::BaseClass();");
        }
    }
    public class DerivedClass : BaseClass
    {
        public int num;
        public DerivedClass(int x)
        {
            num = x;
            System.Console.WriteLine("DerivedClass::DerivedClass(int x);");
        }
    }
    class Program
    {
        static void Main()
        {
            BaseClass A = new DerivedClass(20);
            //B.num = 20; Erro
            //Mas se converter para DerivedClass e mostrar resultado do 'num':
            DerivedClass B = (DerivedClass)A;
            System.Console.WriteLine(B.num); //Ele mostra o resultado que modificou no construtor! Ué? Por que isso pode?
            /* Resultado:
             * BaseClass::BaseClass();
             * DerivedClass::DerivedClass(int x);
             * 20
             */
            System.Console.ReadKey();
        }
    }
}

The comments in the code are already self-explanatory.

    
asked by anonymous 18.03.2015 / 06:34

1 answer

5

The problem is that your A reference, of type BaseClass , can save a reference to any object of BaseClass , not only DerivedClass . Thus, it is not possible for the compiler to know in advance what the actual type of the object pointed to by A , and thus to know that it has the type DerivedClass (and therefore the num field).

(ok, in that case, it would even be possible if the compiler was "smart", but not in others)

For example, what if you had:

static void teste(BaseClass A) 
{
    System.Console.WriteLine(A.num);
}

static void Main()
{
    teste(new DerivedClass(20)); // tem o campo num
    teste(new BaseClass());      // NÃO TEM o campo num! O que acontece agora?
}

To avoid such problems, the compiler only lets you access the fields it's sure to that are there, hence the error trying to A.num . Formally speaking, the static type of A is BaseClass , and the dynamic type of A at that time of execution is DerivedClass . Because C # is a statically typed language, what counts at the time of accessing an object field is its static type. If it were a dynamically typed language (such as JavaScript, Python, Ruby, etc.) then this command would work - but otherwise would cause a run-time error if the object contained in A did not have the num field.

    
18.03.2015 / 07:04