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.

Virtual member call in a constructor的更多相关文章

  1. ReSharper warning: Virtual member call in a constructor

    1.构造函数的执行顺序是:基类--->派生类 2.如果虚方法被重写后,由于基类中调用了虚方法,此时调用的是最外层的被重写后的虚方法,此时可能会发生异常 举例: class Parent { pu ...

  2. virtual member functions(单一继承情况)

    virtual member functions的实现(就单一继承而言): 1.实现:首先会给有多态的class object身上增加两个members:一个字符串或数字便是class的类型,一个是指 ...

  3. 构造函数 (C++)

    构造函数是一种可初始化其类的实例的成员函数. 构造函数具有与类相同的名称,没有返回值. 构造函数可以具有任意数量的参数,类可以具有任意数量的重载构造函数. 构造函数可以具有任何可访问性(公共.受保护或 ...

  4. 6.Type and Member Basics

    1.The Different Kinds of Type Members 1.Constants:a symbol that identifies a never-changing data val ...

  5. (C/C++ )Interview in English - Virtual

    Q: What is virtual function?A: A virtual function or virtual method is a function or method whose be ...

  6. Copy Constructor的构造操作

    Copy Constructor的构造操作 有三种情况,会以一个object的内容作为另一个class object的初值: 1.  对一个object做显式的初始化操作 class X{…}; X ...

  7. C++对象模型(一):The Semantics of Constructors The Default Constructor (默认构造函数什么时候会被创建出来)

    本文是 Inside The C++ Object Model, Chapter 2的部分读书笔记. C++ Annotated Reference Manual中明确告诉我们: default co ...

  8. C++对象模型——Default Constructor的建构操作(第二章)

    第2章    构造函数语意学 (The Semantics of Constructor) 关于C++,最常听到的一个抱怨就是,编译器背着程序猿做了太多事情.Conversion运算符就是最常被引用的 ...

  9. The Semantics of Constructors: The Default Constructor (默认构造函数什么时候会被创建出来)

    本文是 Inside The C++ Object Model, Chapter 2的部分读书笔记. C++ Annotated Reference Manual中明确告诉我们: default co ...

随机推荐

  1. iOS类似QQ好友展开和合并列表的实现代码

    其实原理就是好友列表合上的时候,将这组的cell数设置为0,展开的时候,在变成原来的,就是这么简单 -(); }

  2. 查找并绘制轮廓[OpenCV 笔记XX]

    好久没有更新了,原谅自己放了个假最近又在赶进度,所以...更新的内容是很靠后的第八章,因为最近工作要用就先跳了,后面会更新笔记编号...加油加油! 在二值图像中寻找轮廓 void cv::findCo ...

  3. 回溯算法之n皇后问题

    今天在看深度优先算法的时候,联想到DFS本质不就是一个递归回溯算法问题,只不过它是应用在图论上的.OK,写下这篇博文也是为了回顾一下回溯算法设计吧. 学习回溯算法问题,最为经典的问题我想应该就是八皇后 ...

  4. Pulltorefresh使用中碰到的问题

    第一 在使用XScrollView布局是,无法在该布局.xml文件,放置内容布局控件,假如放置了会报错, <com.markmao.pulltorefresh.widget.XScrollVie ...

  5. svg学习笔记(一)

    SVG——可扩展适量图形,基于XML PC端:IE9+   wap端:表现良好,适合使用 基础图形: line(线段)  <line x1="25" y1="150 ...

  6. MySQL中SQL语句的分类

    1:数据定义语言(DDL) :创建和删除数据库(CREATE DATABASE || DROP  DATABASE):2:创建.修改.重命名.删除表(CREATE  TABLE || ALTER TA ...

  7. FolderBrowserDialog(文件夹浏览对话框)

    1.选择数据库目录,在此处不需要新建文件夹,因此屏蔽新建文件夹按钮. C#代码 FolderBrowserDialog df = new FolderBrowserDialog(); //设置文件浏览 ...

  8. 网络设备作用和工作ISO层

    物理层——中继器和集线器 二者都起数字信号放大和中转的作用. 中继器 Repeater 用来延长网络距离的互连设备.REPEATER可以增强线路上衰减的信号,它两端即可以连接相同的传输媒体,也可以连接 ...

  9. Python的进程间通信

    进程间通讯有多种方式,包括信号,管道,消息队列,信号量,共享内存,socket等 1.共享内存 Python可以通过mmap模块实现进程之间的共享内存 mmap文件对象既像一个字符串也像一个普通文件对 ...

  10. MSSql ID自动增长删除数据重1开始

    dbcc checkident('db_Tome1.dbo.员工信息表',reseed,0) 注:dbcc checkident('表名',reseed,0)