C# 实例化子类的步骤问题

问题描述

classA{publicA(){Say();}publicvirtualvoidSay(){Console.WriteLine("A的虚函数");}}classB:A{privateintnumOne=3;privateintnumTwo;publicB(){Console.WriteLine("B构造函数");}publicoverridevoidSay(){Console.WriteLine("NumOne={0},NumTwo={1}",numOne,numTwo);}}classProgram{staticvoidMain(string[]args){BmyB=newB();Console.Read();}}

楼主这里有两个问题:1.实例化子类B,首先要调用A类的构造函数,这里A的构造函数会调用到A的虚函数Say(),为什么不执行A的虚函数体,而会跑去执行B的重写overrideSay()啊?2.在执行overrideSay()的时候,不是还没有调用B的构造函数么,那岂不是还没有给实例化B类在堆上分配内存?那那两个privatenum1,和num2,的值是怎么保存起来的啊?他们又不是静态变量..

解决方案

解决方案二:
1、虚函数是找这个实例所在类的实现,如果没有才再找父类中的实现2、实例化是先分配内存,再调用构造函数,你可以感受下下面的代码classA{protectedinti=1;publicA(){Say();}publicvirtualvoidSay(){}}classB:A{publicB(){i=2;}publicoverridevoidSay(){Console.WriteLine("i="+i);}}

解决方案三:
B对say函数进行了重写,所以B调用构造函数时,调用了B的构造函数,大多数情况下,虚函数一般是没有方法体的,即什么都不做,具体操作留给继续类来实现。类初始化的时候会先分配内存,在构造函数执行前变量已经分配了内存
解决方案四:
在构造方法中调用虚方法本来就是一件危险的事情,这个时候子类构造尚未调用,如果子类重写的虚方法想当然的认为类成员应该已经初始化过,就可能出问题。所以一般设计时应该避免在构造中调用虚方法,如果无法避免,那么虚方法必须仔细实现,并给继承者有文档说明。
解决方案五:
引用3楼github_22161131的回复:

在构造方法中调用虚方法本来就是一件危险的事情,这个时候子类构造尚未调用,如果子类重写的虚方法想当然的认为类成员应该已经初始化过,就可能出问题。所以一般设计时应该避免在构造中调用虚方法,如果无法避免,那么虚方法必须仔细实现,并给继承者有文档说明。

没听懂。。
解决方案六:
比如你写了一个抽象的写入器Writer类,封装在一个程序集中给别人用,这个类如下:abstractclassWriter{protectedWriter(){Write(0);}publicabstractvoidWrite(intval);}

如果没有说明,别人并不知道它会在构造中就调用Write方法,于是他这样子写了一个子类:classListWriter:Writer{List<int>_list;publicListWriter(){_list=newList<int>();}publicoverridevoidWrite(intval){_list.Add(val);}}

看起来没有问题,结果newListWriter();就会抛出NullReferenceException,准备去揍Writer类的作者。改成下面的样子可以解决问题:classListWriter:Writer{List<int>_list=newList<int>();publicoverridevoidWrite(intval){_list.Add(val);}}

不过这并不适用于所有情况(字段初始化会优先于构造运行,但只能是简单的表达式,无法初始化复杂对象)。所以Writer类的设计是失败的,需要根据情况修改。

时间: 2024-09-22 12:28:01

C# 实例化子类的步骤问题的相关文章

JavaScript的实例化与继承:请停止使用new关键字

JavaScript中的new关键字可以实现实例化和继承的工作,但个人认为使用new关键字并非是最佳的实践,还可以有更友好一些的实现.本文将介绍使用new关键字有什么问题,然后介绍如何对与new相关联的一系列面向对象操作进行封装,以便提供更快捷的.更易让人理解的实现方式. 传统的实例化与继承 假设我们有两个类,Class:function Class() {}和SubClass:function SubClass(){},SubClass需要继承自Class.传统方法一般是按如下步骤来组织和实现

java继承 在子类中声明同名变量的问题???

问题描述 java继承 在子类中声明同名变量的问题??? 如下代码: class Person { String name; int age; public void introduce(){ System.out.println("姓名是" + name + ",年龄是" + age); } } public class Students extends Person{ // String name; public static void main(String[

Java通过反射实例化泛型类的问题

问题描述 Java语言中,想通过反射实例化一个抽象类的子类,问题也可以简化点,可以建个类继承这个抽象类,然后实例化子类.public abstract class MyClass<T> { MyClass() { }}在代码中可以这么写:new MyClass<String>() {}但是如果通过反射,怎么把String这个type传进去,或者通过反射获得constructor,怎么把泛型信息传进去:下面这个是个错误的写法,只是说明要实现的内容:new MyClass<Cla

C#基础知识—父类和子类的关系

基础知识一: using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace WindowsFormsApplication2 { public class ParentClass { public ParentClass() { } public string NamePropety { get; set; } public string GetNa

PHP接口与抽象学习实例

  每次学习到接口和抽象的时候,都会犯蒙,搞不懂他们两个之间到底有什么区别和用途.今天就搬着书本整理下思路拿出来,希望对新学习PHP的朋友们有所帮助. 1.php 接口类:interface 其实他们的作用很简单,当有很多人一起开发一个项目时,可能都会去调用别人写的一些类,那你就会问,我怎么知道他的某个功能的实现方法是怎么命名的呢,这个时候php接口类就起到作用了,当我们定义了一个接口类时,它里面的方式是下面的子类必须实现的,比如 : 代码如下: interface Shop { public

php 接口类与抽象类的实际作用_php技巧

1.php 接口类:interface 其实他们的作用很简单,当有很多人一起开发一个项目时,可能都会去调用别人写的一些类,那你就会问,我怎么知道他的某个功能的实现方法是怎么命名的呢,这个时候php接口类就起到作用了,当我们定义了一个接口类时,它里面的方式是下面的子类必须实现的,比如 : 复制代码 代码如下: interface Shop { public function buy($gid); public function sell($gid); public function view($g

一道java面试题

问题描述 最近我们公司招人,看了下笔试题,有道题不理解题目如下classSuperClass{privateintnumber;publicSuperClass(){this.number=0;}publicSuperClass(intnumber){this.number=number;}publicintgetNumber(){number++;returnnumber;}}classSubClass1extendsSuperClass{publicSubClass1(intnumber){

Python 进阶_OOP 面向对象编程_类和继承

目录 目录 类 最简单的类 类方法 构造器 __init__ 创建一个类 实例化一个对象 调用实例的方法和属性 创建子类 使用 super 来调用父类的构造器 实例化子类对象 调用子类的属性和方法 类属性方法的命名规则 类 类是实例的抽象, 实例是类的具体化. Python 中的类分为 经典类 和 新式类. 前者现在已经很少用到了, 其特点就是可以不需要继承任何父类:后者则刚好相反, 形式类必须至少有一个父类, 如果没有特定的父类需要继承时, 至少需要继承基类 object, 在后面给出例子.

php面向对象编程学习笔记

(OOP)来开发.面向对象开发相对于面向过程有很多优点: 维护简单   模块化是面向对象编程中的一个特征.实体被表示为类和同一名字空间中具有相同功能的类,我们可以在名字空间中添加一个类而不会影响该名字空间的其他成员. 可扩充性   面向对象编程从本质上支持扩充性.如果有一个具有某种功能的类,就可以很快地扩充这个类,创建一个具有扩充的功能的类. 代码重用   由于功能是被封装在类中的,并且类是作为一个独立实体而存在的,提供一个类库就非常简单了. 它比较适合多人合作来开发项目,所以现在很多大中型网站