继承、封装和多态
是面向对象编程的重要特性。
其成员被继承的类叫基类也称父类,继承其成员的类叫派生类 也称子类。
继承是可以传递的。 即:
试想一下,当基类Sum()方法是私有时,派生类还会继承该方法吗?
经过本人测试,没有在B类找到该方法,那么是不是它就没有被继承呢? 其实不是的,私有成员其实已经被继承了,
但是它们却不可以被访问,因为私有成员只能被声明它们的类或结构体中才可访问,所以看上去像是没有被继承。
如果我们想降低访问基本,我们可以把基类Sum()方法定义为protected。
能够阻止 某个类被其他类继承吗?
答案是可以的,C#提供了一个 sealed 修饰符 , 此修饰符会阻止其他类从该类继承。
如果基类定义了带有参数的构造函数,那么此构造函数必须被执行,且在派生类中实现该构造函数,此时我们可以使用base关键字
由此可见:
派生类隐式执行基类中带有参数的构造函数,在程序中基类定义了带有参数的构造函数,
在其派生类中被继承,并使用 base 关键字调用基类中的构造函数来传送参数。
其成员被继承的类叫基类也称父类,继承其成员的类叫派生类 也称子类。
派生类隐式获得基类的除构造函数和析构函数以外的所有成员。
派生类只能有一个直接基类,所以C#并不支持多重继承,但一个基类可以有多个直接派生类。继承是可以传递的。 即:
如果 ClassB 派生出 ClassC,ClassA 派生出 ClassB,则 ClassC 会继承 ClassB 和 ClassA 中声明的成员。
class
A
{
public void Sum( int i, int j)
{
int sum = i + j;
Console.WriteLine( " I am A ,my sum ={0} " ,sum);
}
}
class B : A
{
public void Minus( int i, int j)
{
int minus = i - j;
Console.WriteLine( " I am B ,my minus ={0} " , minus);
}
class InheritanceTest1
{
static void Main( string [] args)
{
B b = new B();
b.Minus( 3 , 4 );
Console.Read();
}
}
{
public void Sum( int i, int j)
{
int sum = i + j;
Console.WriteLine( " I am A ,my sum ={0} " ,sum);
}
}
class B : A
{
public void Minus( int i, int j)
{
int minus = i - j;
Console.WriteLine( " I am B ,my minus ={0} " , minus);
this.Sum(3, 4);
}
}
class InheritanceTest1
{
static void Main( string [] args)
{
B b = new B();
b.Minus( 3 , 4 );
Console.Read();
}
}
结果:I am B ,my minus=-1
I am A ,my sum =
7
经过本人测试,没有在B类找到该方法,那么是不是它就没有被继承呢? 其实不是的,私有成员其实已经被继承了,
但是它们却不可以被访问,因为私有成员只能被声明它们的类或结构体中才可访问,所以看上去像是没有被继承。
如果我们想降低访问基本,我们可以把基类Sum()方法定义为protected。
能够阻止 某个类被其他类继承吗?
答案是可以的,C#提供了一个 sealed 修饰符 , 此修饰符会阻止其他类从该类继承。
sealed
class
A
{
int test;
public void Sum( int i, int j)
{
int sum = i + j;
Console.WriteLine( " I am A ,my sum ={0} " ,sum);
}
}
class B : A
{
public void Minus( int i, int j)
{
int minus = i - j;
Console.WriteLine( " I am B ,my minus ={0} " , minus);
this .Sum( 3 , 4 ); //编译器会报错
}
}
{
int test;
public void Sum( int i, int j)
{
int sum = i + j;
Console.WriteLine( " I am A ,my sum ={0} " ,sum);
}
}
class B : A
{
public void Minus( int i, int j)
{
int minus = i - j;
Console.WriteLine( " I am B ,my minus ={0} " , minus);
this .Sum( 3 , 4 ); //编译器会报错
}
}
前面说过,派生类隐式获得基类的除构造函数和析构函数以外的所有成员。
那么我们该如何获得基类的构造函数和自身的构造函数呢?
我们知道基类的初始化工作由基类的构造函数完成,派生类的初始化工作则有派生类的构造函数完成,
但是这样就产生了派生类构造函数的执行顺序问题。
当基类没有构造函数,派生类也没有构造函数时,都会默认一个空的构造函数,初始化工作发生在定义对象的时候。
public
class
A
{
int test = 0 ;
public void sum()
{
test ++ ;
Console.WriteLine( " I am test ={0} " ,test);
}
}
class B : A
{
int i;
public void PrintInt()
{
i = 3 ;
Console.WriteLine( " I am i ={0} " , i);
}
}
class InheritanceTest1
{
static void Main( string [] args)
{
B b = new B();
b.PrintInt();
Console.Read();
}
}
{
int test = 0 ;
public void sum()
{
test ++ ;
Console.WriteLine( " I am test ={0} " ,test);
}
}
class B : A
{
int i;
public void PrintInt()
{
i = 3 ;
Console.WriteLine( " I am i ={0} " , i);
}
}
class InheritanceTest1
{
static void Main( string [] args)
{
B b = new B();
b.PrintInt();
Console.Read();
}
}
结果:I am i=3
如果只有派生类定义构造函数时,只需构造派生类对象即可。对象的基类部分使用默认构造函数来自动创建。
当基类和派生类都定义有构造函数时,那么执行顺序会怎样呢?
由此可以看见,基类的构造函数被执行,在派生类中被调用。
如果基类中是没有参数的构造函数
如果基类中是没有参数的构造函数,在派生类中可以自定义有参数的构造函数
public
class
A
{
int test = 0 ;
public A()
{
test = 5 ;
Console.WriteLine( " I am A 公有默认构造函数 ,test={0} " , test);
}
}
class B : A
{
}
class InheritanceTest1
{
static void Main( string [] args)
{
B b = new B();
Console.Read();
}
}
{
int test = 0 ;
public A()
{
test = 5 ;
Console.WriteLine( " I am A 公有默认构造函数 ,test={0} " , test);
}
}
class B : A
{
}
class InheritanceTest1
{
static void Main( string [] args)
{
B b = new B();
Console.Read();
}
}
结果:I am A 公有默认构造函数 ,test=5
如果基类定义了带有参数的构造函数,那么此构造函数必须被执行,且在派生类中实现该构造函数,此时我们可以使用base关键字
class
A
{
int test = 0 ;
public A( int i)
{
test = i;
Console.WriteLine( " I am A 公有有参构造函数 ,test={0} " , test);
}
}
class B : A
{
public B( int j): base (j)
{
Console.WriteLine( " I am B 公有有参构造函数,j={0} " ,j);
}
}
class InheritanceTest1
{
static void Main( string [] args)
{
B b = new B( 1 );
Console.Read();
}
}
{
int test = 0 ;
public A( int i)
{
test = i;
Console.WriteLine( " I am A 公有有参构造函数 ,test={0} " , test);
}
}
class B : A
{
public B( int j): base (j)
{
Console.WriteLine( " I am B 公有有参构造函数,j={0} " ,j);
}
}
class InheritanceTest1
{
static void Main( string [] args)
{
B b = new B( 1 );
Console.Read();
}
}
结果:I am A 公有有参构造函数 ,test=1
I am B 公有有参构造函数,j=1
在其派生类中被继承,并使用 base 关键字调用基类中的构造函数来传送参数。
我们可以从代码中看到在创建派生类的对象后,程序首先运行的是基类的构造函数中的内容,然后才是派生类中的内容。
如果派生类的基类也是派生类,则每个派生类只需负责其直接基类的构造,不负责间接基类的构造,
并且其执行构造函数的顺序是从最上面的基类开始的,直到最后一个派生类结束。
并且其执行构造函数的顺序是从最上面的基类开始的,直到最后一个派生类结束。