Reputation: 355
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
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
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.
fun
points to
base::fun
, therefore, 1 is printed when you call fun()
fun
to
point to derived::fun
. Next time you call fun()
it prints 2MSDN 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
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