创建子类的实例是否会创建父类的实例?

时间:2018-11-20 15:01:00

标签: c# .net

我是C#的新手,我想知道,如果我创建子类的实例,它还会自动创建父类的实例吗?

这是我的代码:

class Program
{

    public class ParentClass
    {
        public ParentClass()
        {
            Console.WriteLine("ChildClass uses my Ctor ");
        }

    }

    public class ChildClass : ParentClass
    {
        public ChildClass()
        {
            Console.WriteLine("SaySomething");
        }
    }

    public static void Main()
    {
        ChildClass child = new ChildClass();
    }
}

8 个答案:

答案 0 :(得分:63)

  

它还会自动创建Parent类的实例吗?

不是单独的实例;讨论继承时,ChildClass ParentClass实例。

换句话说,这就像:

  

在创建狗时,我们还会创建动物的实例吗?

我们不创建狗,而是分别创建动物。狗动物实例。如果我们创建了贵宾犬,则贵宾犬狗,动物。

答案 1 :(得分:9)

否,不是,但是它调用了基本构造函数(父类的构造函数)。在您的情况下它是空的,因此编译器将为您完成对基类构造函数的调用:

class Program
{
    public class ParentClass
    {
        public ParentClass()
        {
            Console.WriteLine("ChildClass drived from me ");
        }

    }

    public class ChildClass : ParentClass
    {
        public ChildClass() : base() // base() call is voluntary
        {
            Console.WriteLine("This also use my Ctor");
        }
    }

    public static void Main()
    {
        ChildClass child = new ChildClass();
    }
}

但是,如果您的基类没有无参数构造函数,则必须调用它

class Program
{
    public class ParentClass
    {
        public ParentClass(string foo)
        {
            Console.WriteLine("ChildClass drived from me ");
        }

    }

    public class ChildClass : ParentClass
    {
        public ChildClass() : base("some foo") // base call is obligatory
        {
            Console.WriteLine("This also use my Ctor");
        }
    }

    public static void Main()
    {
        ChildClass child = new ChildClass();
    }
}

根据定义,当ChildClass继承形式ParentClass时,则ChildClass对象也属于ParentClass

如果您的命名更注重现实生活,那将更容易理解。

class Animal {}
class Cat : Animal {}

var rocky = new Cat();

看,岩石是猫,但是也是是动物。

答案 2 :(得分:8)

您问题的实际答案是

  

“否”,它是Child类的实例,而不是Parent类的实例。

但是,如果您的问题是:“您将拥有一个包含Parent类所有属性的实例对象”,答案是

  

“是”,您将拥有在   将父类复制到Child实例中。

答案 3 :(得分:3)

专门讨论您的代码:

class Program
{

    public class ParentClass
    {
        public ParentClass()
        {
            Console.WriteLine("ParentClass constructor is called");
        }

    }

    public class ChildClass : ParentClass
    {
        public ChildClass()
        {
            Console.WriteLine("ChildClassConstructor is called");
        }
    }

    public static void Main()
    {
        //will print that the Parent ctor is called, followed by printing that the child ctor is called
        ChildClass child = new ChildClass();

        //will print that the Parent ctor is called, followed by printing that the child ctor is called
        ParentClass childinparentbox = new ChildClass();

        //will print that the Parent ctor is called
        ParentClass parent = new ParentClass();

        //At this point there are 3 object instances in memory


        //by the way, this can't be done. Can't store a parent in a child: a parent is-not-a child
        ChildClass parentinchildbox = new ParentClass();


    }
}

我更改了消息以使它们与提出的要点相关:

构造函数只是在创建新对象时强制调用的方法。您可以使用它来设置新对象以供使用,初始化属性等。类在C#中是分层的-一切始终都是某些事物的子类,有时甚至是Object。您的parentClass是Object的子代,只是没有说。您的孩子被宣布为父母的孩子

正如其他人指出的那样,使用new时不会得到多个对象实例,而无论您要求创建什么对象,都只会得到一个实例。子类始终可以被引用/“存储在”声明为父类型的变量中。这是因为事物在“子”->“父”的方向上具有“是”关系。狗是动物,猫是动物,动物是物体。他们在相反的方向上没有关系。您不能普遍地说汽车是法拉利,或者某些动物是狗。

因此,事情追逐到层次结构中,您可以将Cat或Dog存储在声明为包含Animal的变量内。动物可能有一个GetNumberOfLegs()方法,该方法报告腿的数量。猫和狗将分别返回4,猴子将返回2。

面向对象编程的主要原则之一是您可以以通用方式引用事物。所有动物的腿都有一定数量。如果是存储在动物中的猫/狗,则GetNumberOfLegs()返回4,如果是猴子,则返回2。但是,如果您感兴趣的只是它,则不需要特别知道它是猫,狗,猴子腿数。这将在以后的讲座中详细介绍,因此我不需要在这里深入了解。我详细说明了为什么我们甚至想要建立层次结构,拥有Animal,创建Dog并将其存储在Animal类型的变量中。我们之所以这样做,是因为我们通常不希望具体细节,而是希望以一种通用的方式引用事物。我们定义了我们关心的通用事物,而特定事物则适合模具。你可以开车。您无需专门学习如何驾驶福特或雪佛兰,因为它们的方向盘和踏板位于相同的位置/布置。您可以操作通用界面。您无需担心转向的实现方式-液压,齿条和小齿轮,Pitman臂-您只需关心的是,当车轮“像这样”转动时,汽车就会像“那样”行驶。

回到您的要求:

因为子代是-父代是-对象,所以当您创建一个新子代时,您会看到一个打印输出,表明调用了父级构造函数,而另一个输出则表明了子级构造函数。这并不表示已经在计算机内存中创建了2个对象-构造函数以层次结构中的所有对象(从对象开始,然后是父对象,然后是子对象)的顺序(从前到后)进行调用。之所以这样,是因为任何构造函数代码中的第一件事就是对相关父构造函数的调用。该构造函数代码中的第一件事是对其父对象的调用

因此,运行时从子级开始,然后一直到父级,祖父母,曾祖父母,一直到祖先的顶部,然后向下运行,依次运行每个构造函数中的其余代码,从上到下。这就是为什么您看到调用了Parent构造函数的打印输出,然后看到Child的原因

所有对象都是同一对象,它是多个方法调用。看到两个打印输出并不表示内存中有两个对象,而是一个具有两个方法(两个构造函数方法)的对象,这些方法以递归顺序被调用

答案 4 :(得分:2)

思考类的另一种方法就是将其视为对象的模板。即从此类创建的对象实例应具有此实现逻辑。创建一个类的实例,将采用所有逻辑并将其转换为对象的行为。当您从某个类继承时,基本上是在子类的模板中包括父类的实现逻辑,因此您只是获得了扩展的“模板”。从此模板创建对象实例时,该实例使用子模板,该模板包含父类和子类中定义的逻辑的组合。

常规实例化: 类逻辑->模板->实例

继承: 父类逻辑+子类逻辑->模板->实例

答案 5 :(得分:1)

不,它只会创建子类的实例。

答案 6 :(得分:1)

假设您有家长班Coffee和孩子班Cappucino

class Coffee {}

class Cappucino : Coffee {}

通过发出new Cappucino(),为Cappucino创建一个实例。 Cappucino实际上是咖啡,并且咖啡的属性继承了Cappucino。

没有为Coffee创建单独的实例。

Cappucino通过继承继承了Coffee的功能

答案 7 :(得分:0)

就像这样...您已经创建了ParentClass的实例,但也可以将其强制转换为ChildClass。这是ParentClass实例。