Roger Luo
Roger Luo

Reputation: 355

behaviour of virtual function called in constructor or destructor

I have read the some materials about the different behaviour of virtual function called in constructor or destructor between c++ and c#. And i test the below code to confirm that c# could call the virtual dirived virtual function as its object exists before the constructor. However i found that the result is same as the similar code in c++. Could any one tell me the reason that why the c# could not display "22" but just "12".

C# code

public class Base
{
    public Base() { fun(); }
    public virtual void fun() { Console.WriteLine(1); }
}
public class Derived : Base
{
    public Derived() { fun(); }
    public virtual void fun() { Console.WriteLine(2); }
}

C++ code

class Base
{
public:
    Base(){fun();}
    virtual void fun(){cout<<1;}
};
class Derived : Base
{
public:
    Derived(){fun();}
    virtual void fun(){cout<<2;}
};

the output result of both c++ and C# is "12".

Upvotes: 3

Views: 1254

Answers (3)

Salvatore Previti
Salvatore Previti

Reputation: 9070

You have an error in your C# code.

To override a C# function you have to specify the override keyword. If you write again virtual you are shadowing the base function, but without the new keyword you should get a warning.

If both are declared virtual, you have two functions with the same name!

Let's do an example...

public class Base
{
    public Base() { fun(); }
    public virtual void fun() { Console.Write(1); }
}

public class Derived : Base
{
    public Derived() { fun(); }
    public override void fun() { Console.Write(2); }
}

public class DerivedWithError : Base
{
    public DerivedWithError() { fun(); }
    public new virtual void fun() { Console.Write(3); }
}

...

// This will print "22".
Base normal = new Derived();
Console.WriteLine();

// This will print "13" !!!
Base withError = new DerivedWithError ();
Console.WriteLine();

// Let's call the methods and see what happens!

// This will print "2"
normal.fun();
Console.WriteLine();

// This will print "1" !!!
withError.fun();
Console.WriteLine(); 

Shadowing means "add a new method with the same name without using polymorfism". Without the override keyword you are disabling polymorfism.

So everything should be clean and easy to understand now.

DerivedWithError.fun() is a totally new virtual method. It have the same name of the function fun in base class, but they are not related!

Speaking from the point of view of the virtual table (or virtual method table if you prefer another name), with shadowing the base function and the derived function occupy two different entries in the virtual table, also if they have the same name. If you use override instead, you are forcing the func method in derived class to overwrite the virtual table entry occupied by Base.func, and this is polymorphism.

Dangerous but allowed by .NET, be careful with the syntax, always!

You can call virtual functions in constructors in C#, usually however in derived class if a method is called in base constructor you should be careful on how you use fields in derived class. Now, to be clean and avoid confusion and risk, you should avoid to call virtual methods in constructors, but in reality it is very useful several time.

For example the so called "Factory methods" that does not access to any variable.

public abstract class MyClass
{
    public IList<string> MyList { get; private set; }

    public MyClass()
    {
         this.MyList = this.CreateMyList();
    }

    protected abstract IList<string> CreateMyList();
}

public class MyDerived : MyClass
{
    protected override IList<string> CreateMyList()
    {
        return new ObservableCollection<string>();
    }
}

This is perfectly legal and it works!

Upvotes: 2

Dave Hillier
Dave Hillier

Reputation: 19083

I'm assuming you're creating an instance of derived in each case.

Part of your problem is that it is not advised to call virtual methods during the constructor.

  1. The base constructor is called. Part the first thing this constructor does is initialise the VTable fun points to base::fun, therefore, 1 is printed when you call fun()
  2. Then the derived constructor initialises the vtable to override fun to point to derived::fun. Next time you call fun() it prints 2

MSDN strongly advises against this: Do not call overridable methods in constructors

Effective C++ makes and even stronger suggestion: Never Call Virtual Functions during Construction or Destruction

This is a similar question

Upvotes: 0

mironych
mironych

Reputation: 2978

The problem is that even if functions have the same name "fun()" each is member of class in what it is declared. So when you call fun() from base class ctor you are calling Base.func(), when you are calling fun() from derived class it is like Derived.fun(); If you want to output "22" you need to override fun() in Derived class.

     public class Derived : Base
    {
        public Derived() { fun(); }
        public override void fun() { Console.WriteLine(2); }
    }

Upvotes: 1

Related Questions