zoukankan      html  css  js  c++  java
  • Virtual member call in a constructor

    http://stackoverflow.com/questions/119506/virtual-member-call-in-a-constructor

    (Assuming you're writing in C# here)

    When an object written in C# is constructed, what happens is that the initializers run in order from the most derived class to the base class, and then constructors run in order from the base class to the most derived class (see Eric Lippert's blog for details as to why this is).

    Also in .NET , objects do not change type as they are constructed, but start out as the most derived type, with the method table being for the most derived type. This means that virtual method calls always run on the most derived type.

    When you combine these two facts you are left with the problem that if you make a virtual method call in a constructor, and it is not the most derived type in its inheritance hierarchy, that it will be called on a class whose constructor has not been run, and therefore may not be in a suitable state to have that method called.

    This problem is, of course, mitigated if you mark your class as sealed to ensure that it is the most derived type in the inheritance hierarchy - in which case it is perfectly safe to call the virtual method.

    在父类的构造函数中,调用virtual方法的时候。

    父类的构造函数,可能是因为子类构造的时候,默认调用了父类的无参构造函数导致的。

    最终调用virtual方法的结果是调用的子类override的方法,这是不合适的。因为此时子类尚未构造

    第二个解答

    In order to answer your question, consider this question: what will the below code print out when the Child object is instantiated?

    abstract class Parent
            {
                protected Parent()
                {
                    DoSomething();
                }
    
                protected abstract void DoSomething();
            }
    
            class Child : Parent
            {
                private string foo;
                public Child() { foo = "HELLO"; }
                protected override void DoSomething()
                {
                    Console.WriteLine(foo.ToLower());
                }
            }

    The answer is that in fact a NullReferenceException will be thrown, because foo is null. 

    An object's base constructor is called before its own constructor.      //基类的构造函数,在子类的构造函数之前被调用

    By having a virtual call in an object's constructor you are introducing the possibility that inheriting objects will execute code before they have been fully initialized.

     

    Why Do Initializers Run In The Opposite Order As Constructors? Part One

    http://blogs.msdn.com/b/ericlippert/archive/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one.aspx

    Pop quiz!

    What do you expect the output of this program to be?

    using System;

    class Foo
    {
        public Foo(string s)
        {
            Console.WriteLine("Foo constructor: {0}", s);
        }
        public void Bar() { }

    class Base
    {
        readonly Foo baseFoo = new Foo("Base initializer");
        public Base()
        {
            Console.WriteLine("Base constructor");
        }

    class Derived : Base
    {
        readonly Foo derivedFoo = new Foo("Derived initializer");
        public Derived()
        {
            Console.WriteLine("Derived constructor");
        }

    static class Program
    {
        static void Main()
        {
            new Derived();
        }
    }

    I got a question from a user recently noting that the order was not as he expected. One naively expects that the order will go "base initializers, base constructor body, derived initializers, derived constructor body". In fact the order actually is that first all the initializers run in order from derived to base, and then all the constructor bodies run in order from base to derived.

    The latter bit makes perfect sense; the more derived constructors may rely upon state initialized by the less derived constructors, so the constructors should run in order from base to derived. But most people assume that the call sequence of the code above is equivalent to this pseudocode:

    // Expected
    BaseConstructor()
    {
        ObjectConstructor();
        baseFoo = new Foo("Base initializer");
        Console.WriteLine("Base constructor");

    DerivedConstructor()
    {
        BaseConstructor();
        derivedFoo = new Foo("Derived initializer");
        Console.WriteLine("Derived constructor");
    }

    When in point of fact it is equivalent to this:

     // Actual
    BaseConstructor()
    {
        baseFoo = new Foo("Base initializer");
        ObjectConstructor();
        Console.WriteLine("Base constructor");

    DerivedConstructor()
    {
         derivedFoo = new Foo("Derived initializer");
        BaseConstructor();
        Console.WriteLine("Derived constructor");
    }

    That explains the mechanism whereby the initializers run in order from derived to base and the constructor bodies run in the opposite order, but why did we choose to implement that mechanism instead of the more intuitively obvious former way?

    Puzzle that one over for a bit, and then read on for a hint.

    ...

    ...

    ...

    The "readonly" modifiers in there were no accident. The code gives the appearance that any call to derivedFoo.Bar() andbaseFoo.Bar() should never fail with a null dereference exception because both are readonly fields initialized to non-null values.

    1. Is that appearance accurate, or misleading?
    2. Now suppose initializers ran in the "expected" order and answer question (1) again. 

    I'll post the answers and analysis next week. Have a fabulous weekend!

    Why Do Initializers Run In The Opposite Order As Constructors? Part Two

    http://blogs.msdn.com/b/ericlippert/archive/2008/02/18/why-do-initializers-run-in-the-opposite-order-as-constructors-part-two.aspx

    As you might have figured out, the answer to last week's puzzle is "if the constructors and initializers run in their actual order then an initialized readonly field of reference type is guaranteed to be non null in any possible call. That guarantee cannot be met if the initializers run in the expected order."

    Suppose counterfactually that initializers ran in the expected order, that is, derived class initializers run after the base class constructor body. Consider the following pathological cases:

    class Base
    {
        public static ThreadsafeCollection t = new ThreadsafeCollection();
        public Base()
        {
            Console.WriteLine("Base constructor");
            if (this is Derived) (this as Derived).DoIt(); 
            // would deref null if we are constructing an instance of Derived
            Blah(); 
            // would deref null if we are constructing an instance of MoreDerived
            t.Add(this);
            // would deref null if another thread calls Base.t.GetLatest().Blah();before derived constructor runs
        }
        public virtual void Blah() { }

    class Derived : Base
    {
        readonly Foo derivedFoo = new Foo("Derived initializer");
        public DoIt()
        {
            derivedFoo.Bar();
        } 
    }
    class MoreDerived : Derived
    {
        public override void Blah() { DoIt(); }


    Calling methods on derived types from constructors is dirty pool, but it is not illegal. And stuffing not-quite-constructed objects into global state is risky, but not illegal. I'm not recommending that you do any of these things -- please, do not, for the good of us all. I'm saying that it would be really nice if we could give you an ironclad guarantee that an initialized readonly field is always observed in its initialized state, and we cannot make that guarantee unless we run all the initializers first, and then all of the constructor bodies.

    Note that of course, if you initialize your readonly fields in the constructor, then all bets are off. We make no guarantees as to the fields not being accessed before the constructor bodies run.

    Next time on FAIC: how to get a question not answered.

  • 相关阅读:
    分部视图
    linq的几个方法
    如何让服务器支持mp4文件下载和sqlserver将表生成为sql语句方法
    在asp.net mvc中导出Excel文件
    Linq2EF操作中的两个小问题
    JSON到底是什么?
    连接跟踪(conntrack):原理、应用及 Linux 内核实现 转载
    没有安全,没有隐私
    互联网发展到今天,我们要做的,是用机器解决人类解决不了的问题。在这个意义上,比起人工智能,机器智能这个词更加准确。
    今天,世界各国城市的可持续发展面临很大挑战,这些挑战也带来了一个难得的机遇,就是利用机器智能解决城市发展过程中许多重要的问题,如交通治理。同时这也是像机器智能这样的新一代技术快速发展的机遇,这正是我全身心推动城市大脑的原因
  • 原文地址:https://www.cnblogs.com/chucklu/p/4826781.html
Copyright © 2011-2022 走看看