c#面对对象的三大特性
2017-03-30 15:44:30 duanworld 阅读数 553
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/*
 * C#三大特性
 * 封装:
 * 就是吧一个对象所能操作的所有信息放在一起;这样的方法包含在类中,通过类的实例来实现;
 * 作用:
 * 1.良好的封装能够减少耦合(比如实现界面和逻辑分离);
 * 2.可以让类对外接口不变,内部可以实现自由的修改;
 * 3.类具有清晰的对外接口,使用者只需要调用,无需关心内部;
 * 4.因为封装的类功能相对独立,因此能更好的实现代码复用;
 * 5.可保护代码不被无意中破坏,通过私有字段等实现内部,注意:这里的代码保护不是指代码本身的加密,而是对不想外部更改的代码通过私有实现;
 * 继承:
 * 在现有类(基类、父类)上建立新类(派生类、子类)的处理过程为继承;从父辈身上继承点特征;
 * 被继承的类为基类(父类),继承的类为派生类(子类),派生类能自动获取基类(除了构造函数和析构函数和(私有成员)的所有成员),可以在派生类中添加新的属性和方法扩展其功能;
 * 作用:
 * 如果子类属性和父类有一些不一样,那么就不用再费劲见一个新类,可以直接在父类基础上修改就行了,免去了很多操作,不用重复定义类;
 * 语法:
 * 子类:父类
 * 一个子类只能有一个父类(只能继承一个类)
 * protected 修饰符(受保护的,只有当前类的成员与继承该类的类 才能访问)
 * 多态:
 * 同一操作作用于不同的对象可以有不同的解释,产生不同的执行效果;
 * 多态的表达方式:
 * 1.使用新的派生成员替换基成员:
 * 如果基类定义了一个方法、字段或属性,则new关键字用于在派生类中创建该方法、字段或属性的新定义;new关键字放置在要替换的类成员的返回类型之前,调用的是新的类成员而不是已被替换的基类成员,这些基类成员成为隐藏成员;如果将派生类的实例强制转换成基类的实例,就仍然可以调用隐藏类成员;
 * 2.虚拟的基成员:
 * 重写:父类中的方法,属性用virtual修饰;子类中对应override修饰
 * 注意:
 *     1.字段不能是虚拟的,只有方法、属性、事件和索引器才可以是虚拟的;
 *     2.子类重写某个虚拟成员时,即使该子类的实例被当作基类的实例访问,也会调用子类的成员;
 *     3.无论在子类和最初声明虚拟成员的类之间已声明了多少个类,虚拟成员都将永远为虚拟成员;如果类A声明了一个虚拟成员,类B从A派生,类C从类B派生,则类C继承该虚拟成员,并且可以选择重写它,而不管类B是否为该成员声明了重写;
 *     4.派生类可以通过将重写声明为密封的来停止虚拟继承,这需要在类成员声明中将sealed关键字方法override关键字的前面;
 * 3.base:可以调用父类的成员方法,除了构造函数和析构函数,派生类将隐式继承了直接基类的所有成员,也可以显示得而调用父类的构造函数来构造子类的成员数据(引申this)
 * 
*/
namespace ConsoleApplication8
{
    class Program
    {
        static void Main(string[] args)
        {
            #region
            //BlackCat blackCat = new BlackCat();
            //blackCat.Run();
            //Console.WriteLine(blackCat.Size);
            //Console.WriteLine(blackCat.name);
            #endregion
            #region
            //Mosquito mosquito = new Mosquito();
            //Console.WriteLine("蚊子大小=" + mosquito.Size());
            //Insect insect = new Insect();
            //Console.WriteLine("昆虫大小=" + insect.size);
            #endregion
            Insect insect = new Mosquito();//父类调用子类的
            insect.Bite();
            Console.WriteLine("昆虫大小=" + insect.size);
            Insect insect1 = new Ant();
            insect1.Bite();
            Console.ReadKey();
        }
    }
    #region
    //class Monitor//简单的封装
    //{
    //    private string brand;//品牌
    //    public string Brand
    //    {
    //        get { return brand; }
    //    }
    //    public string color;//颜色
    //    private int size;//尺寸
    //    public int Size
    //    {
    //        get { return size; }
    //    }
    //    void Show()//显示
    //    { 
    //    }
    //}
    #endregion
    #region
    //猫类
    class Cat
    {
        public Cat()
        {
            Console.WriteLine("我是猫");
        }
        public Cat(int age)//有参的不能被读取
        {
            Console.WriteLine("我是猫,我今年{0}岁");
        }
        ~Cat()
        { 
        
        }
        public string name = "Tom";
        private int size = 10;
        public int Size
        {
            get { return size; }
        }
        public void Run()
        {
            Console.WriteLine("我在跑");
        }
    }
    //黑猫类
    class BlackCat : Cat//继承语法 子类:父类
    {
        public BlackCat()
        {
            Console.WriteLine("我是黑猫");
        }
    }
    #endregion
    #region
    ////昆虫类
    //class Insect
    //{
    //    public int size = 10;
    //    public void Bite()
    //    { 
        
    //    }
    //}
    ////蚊子类
    //class Mosquito : Insect
    //{
    //    public new int size = 20;
    //    public int Size()
    //    {
    //        return size;
    //    }
    //}
    ////蚂蚁类
    //class Ant : Insect
    //{ 
    
    //}
    #endregion
    //昆虫类
    class Insect
    {
        public int size = 10;
        public virtual void Bite()//virtual可以被子类重写,不能写在字段里面
        {
            //加上virtual可以说成是一个虚函数
            Console.WriteLine("我不知道怎么咬人");
        }
    }
    //蚊子类
    class Mosquito : Insect
    {
        public override void Bite()
        {
            size = 20;
            Console.WriteLine("我会叮人");
        }
    }
    //蚂蚁类
    class Ant : Insect
    {
        public sealed override void Bite()//override前面加上sealed是不能被重写的
        {
            Console.WriteLine("我会咬人");
        }
    }
}
2016-11-23 21:02:09 xiaouncle 阅读数 8989

想要学好面向对象编程,除了掌握语法结构外最重要的就是熟悉面向对象三大特性,这三大特性不是相互独立的而是相互关联、你中有我我中有你的关系,想要真正了解三大特性必须把这三部分当做一个整体来考虑。

封装

封装就是通过给类及类中的成员变量、属性和方法设置不同的访问修饰符(public、protected、internal、protected internal、private)来控制它们的作用范围,以达到封装的目的。
各访问修饰符作用范围如下:

访问修饰符 说明
public 公有访问。不受任何限制。
protected 保护访问。只限于本类内部和子类内部可访问,实例不能访问。
internal 内部访问。只限于本项目内访问,其他不能访问。(相当于项目内的public)
protected internal 内部保护访问。只限于本项目和子类访问,其他不能访问。(protected和internal的权限之和)
private 私有访问。只限于本类成员内访问,子类、实例都不能访问。

protected类型解释:
若被引用的程序集中有子类A:B,那A中public类型的属性、方法和B中public类型的属性、方法都既可以通过A的实例或类名来调用,又可以在A内部直接使用,但A、B中protected类型的属性、方法只能在A内部直接使用,不能通过A的实例或类名来调用;
若引用程序集的一方C继承了A,那A、B、C中public类型的属性、方法都既可以通过C的实例或类名来调用,又可以在C内部直接使用,但A、B、C中protected类型的属性和方法只能在C内部直接使用,不能通过的实例或类名来调用。

默认访问修饰符

在命名空间内部的所有类型(class、struct、abstract class、interface、delegate、enum)的访问修饰符默认是internal,可以人为改成public类型,不能改成protected、protected internal、private类型。
1、命名空间内部各类型使用默认访问修饰符
这里写图片描述
ConsoleTest项目引用Encapsulation.dll后
这里写图片描述

2、命名空间内部各类型使用public访问修饰符
这里写图片描述
ConsoleTest项目引用Encapsulation.dll后
这里写图片描述
3、类内部的所有成员,默认均为private类型。
4、抽象类的所有成员,默认均为private类型,但抽象方法不能用private修饰。
5、接口的所有成员,默认均为public类型,而且不能手动添加访问修饰符。
6、结构的所有成员,默认均为private类型,而且只能是public、internal、private这三种类型。

继承

1、被继承的类成为父类、基类、超类,而主动继承的类成为子类或派生类。子类继承父类的状态和行为,同时也有自己的特性。
2、System.Object是所有类型的基类
3、C#中继承的写法,class A:B{ }
4、继承具有传递性,由A:B B:C=>A:C
5、构造方法不能继承
6、C#只允许单继承,一个类只能继承于一个父类
7、密封类不能被继承,例如:sealed class Animal{ }
8、子类不仅继承了父类的公有成员,同时继承了父类的私有成员,只是父类的私有成员在子类中不可被访问。
9、class SubClass:MainClass{ }

SubClass subClass = new SubClass();
subClass.MethodTwo();
subClass.MethodThree();

代码解释:
创建subClass对象时会先执行父类的构造方法,再执行子类的构造方法;
创建subClass对象时默认调用父类的无参构造方法,我们可以显示调用父类的含参构造方法;
subClass.MethodTwo();会直接执行MethodTwo()方法;
subClass.MethodThree();会直接执行MethodThree()方法;
如果MainClass还有父类C,那创建subClass对象时就要首先调用C的构造方法,其次调用MainClass的构造方法,最后调用SubClass的构造方法。
10、当父类和子类中有名称相同的方法时,父类中的方法会被隐藏。
假设父类和子类的重名方法为SayHi,发生隐藏时子类中的写法为public new void SayHi(){ },其实子类的方法不加new也可以,因为发生隐藏时系统默认会自动加上。
11、A:B,A和B都有方法SayHi(),当B中的SayHi()是一个虚方法(virtual)时,才能在子类A中被重写/覆写,通过override关键字重写。
重写是对继承自父类的SayHi()方法进行修改,隐藏与重写的本质是完全不同的。
包含关键字virtual、abstract、override的方法才能被重写,密封方法(sealed)不能被重写。
12、里氏替换原则:子类对象可以赋值给父类变量,反之不成立。
A:B,A和B中都有方法SayHi(),当B b = new A();,b.SayHi();默认情况下(SayHi()没有在A中被重写)根据就近原则调用父类B中的SayHi()方法。如果方法SayHi()在子类中被重写(override),那b.SayHi()调用的就是子类A中的SayHi()方法。
实例解释:
Person p = new Chinese();
p.SayHi();
子类Chinese没有重写SayHi()时,p.SayHi()调用的是父类中的SayHi()方法;
子类Chinese重写了SayHi()时,pSayHi()调用的是子类中的SayHi()方法。
Person p = new Person();
p.SayHi();
无论子类Chinese是否重写了SayHi()方法,p.SayHi()调用的都是Person类中的SayHi()方法。

多态

多态有两种形式:重载、重写/覆写。
1、重载
同一个类中有多个方法的名称相同、参数个数不同或类型不同,则属于重载。
同一个类中有多个方法名称相同、参数个数相同、参数类型相同、返回值类型不同,这样不属于重载,编译时会报错。
这里写图片描述
这里写图片描述
2、重写/覆写
实现重写有三种情况:
普通类中的virtual方法可在子类中被重写;
抽象类中的abstract方法和abstract属性必须直接或间接在子类中被重写;
接口中的所有成员都必须被子类实现。

第一种情况:
(1)当类为普通类时,只有父类的虚方法才能被子类重写,子类实现重写要用关键字override,如果不加override就会隐藏父类的方法,隐藏需要加上关键字new,例如:public new static void a(){}或public static new void a(){}。
(2)静态类中只能有静态成员,非静态类中可以有静态成员和非静态成员。
(3)静态方法不能被重写,但可以被隐藏。
(4)静态成员不能带override、abstract、virtual。

第二种情况:
(1)抽象类中可以有抽象属性、抽象方法和成员实例,继承抽象类的子类必须直接或间接重写所有的抽象方法,而且参数和返回值类型必须完全一致,成员实例可以不被重写。
(2)非抽象类中只能有成员实例。
(3)抽象类不能直接实例化,但是有构造方法,可以利用里氏替换原则把子类对象赋值给抽象的父类变量。
这里写图片描述
这里写图片描述
AbsSubClass absSubClass = new AbsSubClass();
AbsClass absClass = new AbsSubClass();
创建absSubClass对象或absClass对象时,仍然是先执行父类的构造方法,再执行子类的构造方法。
(4)抽象方法必须用abstract修饰,而且不能有方法体。
(5)抽象方法不能用private修饰。

第三种情况:
(1)C#中类是单继承,接口是多继承,如果同时继承类和接口的话,接口必须在基类的后面,否则编译会出错。例如:class SubClass:MainClass,ISay,IEat{ }
(2)接口不能直接实例化,没有构造方法,可以利用里氏替换原则把子类对象赋值给接口类型的父类变量。
这里写图片描述

这里写图片描述
(3)接口中的成员没有访问修饰符,默认是public类型的,而且不能手动添加任何访问修饰符。
(4)实现接口时不需要override,实现接口的类中的方法的参数和返回值类型必须与接口中定义的类型完全一致。
(5)接口命名一般以I开头,表示某种功能,实现某一接口表示具备了某一功能。

三大特性之间的关系

1、继承时父类中的内容需要封装,例如:父类中的某些内容不希望被子类使用,那就需要使用private访问修饰符。
2、重写形式的多态必须依靠继承,不继承是无法实现重写的,这无须多说。
3、继承具有封装功能,继承分普通类、抽象类、接口三种情况,下面举例说明。

普通类继承封装功能实例:
(1)父类截图
这里写图片描述
(2)子类截图
这里写图片描述
(3)测试父类变量可调用的方法
由于MainClass中public类型的方法只有A和B,因此通过MainClass的实例对象只能调用A和B。
这里写图片描述
(4)测试被子类对象赋值的父类变量可调用的方法
虽然SubClass中public类型的方法有A、B、MethodTwo、MethodThree,但是被子类对象赋值的mainClass,只能调用A和B,相当于封装了子类SubClass。
这里写图片描述
(5)测试子类变量可调用的方法
如你所料SubClass类及其父类MainClass中所有的public方法都可以通过SubClass对象调用。
这里写图片描述

抽象类继承封装功能实例:
(1)父类截图
这里写图片描述
(2)子类截图
这里写图片描述
(3)测试被子类对象赋值的抽象的父类变量可调用的方法
虽然AbsSubClass中public类型的方法有A、B、MethodTwo,但是被子类对象赋值的absSubClass,只能调用A和B,相当于封装了子类AbsSubClass。
这里写图片描述
(4)测试子类变量可调用的方法
如你所料AbsSubClass类及其父类AbsClass中所有的public方法都可以通过AbsSubClass对象调用。
这里写图片描述

接口继承封装功能实例:
(1)父类截图
这里写图片描述
(2)子类截图
这里写图片描述
(3)测试被子类对象赋值的接口类型的父类变量可调用的方法
虽然Person中public类型的方法有SayChinese、SayChinese、MethodOne,但是被子类对象赋值的person,只能调用SayChinese和SayChinese,相当于封装了子类Person。
这里写图片描述
(4)测试子类变量可调用的方法
如你所料Person类及其父类ISay中所有的public方法都可以通过Person对象调用。
这里写图片描述

2017-12-05 21:59:03 BG_0001 阅读数 262

昨天阶段考试之后觉得自己对面向对象特性的理解比较模糊就重新找一些资料复习整理。

一、封装
上课笔记:为了数据不能够在外部进行人为的修改,故在设计类的时候把字段写成私有的,对象就不能够直接用“.”运算符点出来进行修改。
封装的功能是防止数据遭到破坏,为了修改数据会:(1)把私有的字段写成属性,这样可以通过属性进行操作(2)另外类里面会把方法写成公有的,然后再方法类里面对私有字段进行操作也可以修改数据
1、定义
把一个或多个项目封闭在一个物理的或逻辑的包中。封装只公开代码单元的对外接口,而隐藏其具体实现,尽量不对外公开代码。使用封装有很多好处,从设计角度来讲,封装可以对外屏蔽一些重要的信息,比如使用电脑的人只要知道怎么使用电脑就可以,不用知道这些功能具体是怎么实现的;从安全性考虑,封装使对代码的修改更加安全和容易,封装明确的指出了哪些属性和方法是外部可以访问的,这样当需要调整这个类的代码时,只要保证公有属性不变,公有方法的参数和返回值类型不变,那么就可以尽情的修改这个类,而不会影响到程序的其他部分;封装还避免了命名冲突的问题,封装有隔离作用,不同的类中可以有相同名称的方法和属性,但不会混淆,也可以减少耦合。

class Enemy
{
    //把字段写成私有的
    private int hp;
    //写出字段的属性
    public int Hp
    {
        get{return hp;}
        set{hp = value;}
    }
    //使用构造方法给字段赋初始值
    //如果类里面只能有一个带参数的构造方法,此时创建对象时就只能调用带参数的构造方法,系统不会自动创建一个无参的构造方法
    public Enemy(int hp)
    {
        this.hp = hp;
    }
    //方法位公有的,通过方法对字段进行操作
    public void BeAttacked()
    {
        this.hp -=20;
    }
}
 class Program
 {
        static void Main(string[] args)
        {
            Enemy enemy = new Enemy (100, 30);
            enemy.Hp = 200;
            enemy.BeAttacked();
            Console.WriteLine (enemy.Hp);
        }
}

二、继承

**上课笔记**:如果不同的类里面有相同的成员,可以把相同的部分抽离出来放到一个公有的类里面,其他的类来继承这个公有的类,所有继承的类都可以使用这个公有的类里面的成员。定义一个公有类,公有的成员放到该类里面,其他类里面把公有的部分删除。
base 关键字用于从派生类中访问基类的成员:
  ● 调用基类上已被其他方法重写的方法。
  ● 指定创建派生类实例时应调用的基类构造函数。
基类访问只能在构造函数、实例方法或实例属性访问器中进行。

C# 中创建派生类的语法如下:

class
{

}
class :
{

}
多重继承就是一个子类可以继承多个父类,如下列:
class
{

}
class
{

}
class : , { … }
这个例子的基类,就是上面描述概念的时候提到的形状,形状是基类,而这个基类是个抽象的概念,而不是具体的,因此是抽象类,此类包含属性形状名称、输出形状周长和面积的方法以及计算形状周长和面积的抽象方法:

    /// <summary>
    /// 形状基类    
    /// </summary>
    public abstract class Shape
    {
        /// <summary>
        /// 形状名称
        /// </summary>
        public string ShapeNameP { get; private set; }

        public Shape(string shapeName)
        {
            ShapeNameP = shapeName;
        }
        /// <summary>
        /// 输出形状周长
        /// </summary>
        /// <param name="permeter"></param>
        public virtual void PrintPerimeter(double permeter)
        {
            Console.WriteLine(ShapeNameP + "Perimeter:"+ permeter);
        }
        /// <summary>
        /// 输出形状面积
        /// </summary>
        /// <param name="area"></param>
        public virtual void PrintArea(double area)
        {
            Console.WriteLine(ShapeNameP + "Area:" + area);
        }
        /// <summary>
        /// 计算形状周长
        /// </summary>
        /// <returns></returns>
        public abstract double CalculatePerimeter();
        /// <summary>
        /// 计算形状面积
        /// </summary>
        /// <returns></returns>
        public abstract double CalculateArea();
    }

下面再来看具体的子类,子类是圆,包含属性半径、计算周长和面积的方法:

    public class Circle : Shape
    {
        public double R { get; set; }

        public Circle():base("Circle")
        {
            R = 0;
        }
        /// <summary>
        /// 圆的周长
        /// </summary>
        /// <returns></returns>
        public override double CalculatePerimeter()
        {
            return 2*Math.PI*R;
        }
        /// <summary>
        /// 圆的面积
        /// </summary>
        /// <returns></returns>
        public override double CalculateArea()
        {
            return Math.PI*R*R;
        }
    }

再来看看长方形,包含属性高度和宽度、计算周长和面积的方法:

    public class Rectangle : Shape
    {
        /// <summary>
        /// 长方形的长度
        /// </summary>
        public double Width { get; set; }

        /// <summary>
        /// 长方形的高度
        /// </summary>
        public double Height { get; set; }

        public Rectangle()
          : base("Rectangle")
        {
            Width = 0;
            Height = 0;
        }

        /// <summary>
        /// 长方形的周长
        /// </summary>
        /// <returns></returns>
        public override double CalculatePerimeter()
        {
            return (Width + Height) * 2;
        }

        /// <summary>
        /// 长方形的面积
        /// </summary>
        /// <returns></returns>
        public override double CalculateArea()
        {
            return Width * Height;
        }
    }

以下是调用的代码:

            Circle circle = new Circle();
            circle.R = 20;

           Rectangle rectangle = new Rectangle();
            rectangle.Height = 30;
            rectangle.Width = 20;

            List<Shape> shapeList = new List<Shape>();
            shapeList.Add(circle);
            shapeList.Add(rectangle);

            foreach (Shape shape in shapeList)
            {
                shape.PrintPerimeter(shape.CalculatePerimeter());
                shape.PrintArea(shape.CalculateArea());
            }

三、多态

这个多态对我目前而言理解还是比较抽象
废话不说先上网上找到的一些资料:
多态是指程序中同名的不同方法共存的情况,主要通过子类对父类方法的覆盖来实现多态。这样,不同类的对象可以用同名的方法完成特定的功能,但具体的实现方法却可以不同。比如说形状包含正方形、长方形、圆等,每个形状都有面积和周长,但是不同的形状计算面积和周长的方法都不同。

下面举例来说明多态
啥也不说先上代码

 enum MenPaiName
    {
        华山派,
        少林派,
        青城派,
        崆峒派,
        武当派,
        丐帮,
        峨眉派,
        昆仑派,
        点苍派,
        雪山派
    }
    class KongFu
    {
        public MenPaiName name { get; set; }
        public float power { get; set; }

        public virtual void Attacked()
        {
            Console.WriteLine("门派攻击-10");
        }
    }

    class  WuDang:KongFu
    {
        public WuDang(MenPaiName name,float power)
        {
            this.name = name;
            this.power = power;
        }

        public float HP { get; set; }

        public void LianGong()
        {
            Console.WriteLine("练功");
        }
    }

    class ShaoLin : KongFu
    {
        public ShaoLin(MenPaiName name, float power)
        {
            this.name = name;
            this.power = power;
        }
    }

    class EMei:KongFu
    {
        public EMei(MenPaiName name, float power)
        {
            this.name = name;
            this.power = power;
        }

        public override void Attacked()
        {
            Console.WriteLine("峨眉派攻击-20");
        }
    }

    class  Race
    {
        public void YaoQing(KongFu kf)
        {

        }
    }
            WuDang wuDang = new WuDang(MenPaiName.武当派, 30);

            ShaoLin shaoLin = new ShaoLin(MenPaiName.少林派, 80);
            EMei eMei = new EMei(MenPaiName.峨眉派, 99);

            wuDang.Attacked();
            shaoLin.Attacked();
            eMei.Attacked();
            //里氏转换原则
            //1、只要是父类所在的地方都可以用子类来赋值,即可以把子类的对象赋值给父类的对象
           //这样方法的参数如果作为父类的类型时,所有的子类都可以传进来,使得我们的方法得到啦进一步的重用
           //但是对象在调用成员时,只能调用父类里面的成员,而子类里面的成员会被屏蔽掉
            KongFu kongFu = new WuDang(MenPaiName.武当派, 60);

            //2、父类可以强制转换成子类。
            WuDang w = (WuDang) kongFu;
            //使用as类型转换符在不同的引用类型之间进行类型转换,如果转换成功对象就是转换后的类型,如果转换不成功对象时空
            KongFu kong = new EMei(MenPaiName.峨眉派, 50);
            WuDang e = kong as WuDang;
            if (e == null)
            {
                Console.WriteLine("e为空");
            } 

            int a = 10;
            //把一个子类型赋值给了一个引用类型,此操作称为装箱操作
            object obj = a;
            //把引用类型转换为值类型的操作称为拆箱操作
            int b = (int) obj;
            Console.WriteLine(b+1);

            /*当我们把子类的对象赋值给父类以后,父类的对象里面存的是子类的对象,调方法时仍然调的是父类里面的方法,这也意味着任何一个子类的对象赋值给父类以后每一个子类调用的方法都一样,每一个子类的行为就体现不出来啦,此时可以把父类里面的方法写成虚方法,然后在子类里面进行重写,这样在调方法后就会调子类重写后的方法,如果子类不重写,就调父类的方法*/
            kong.Attacked();
        }
    }
2017-07-06 17:15:00 weixin_34409822 阅读数 10

一、封装: 我们可以把世界上任何一个东西都看作为一个对象,那么我们这里以人为例,一个人就肯定是一个对象了。 那么封装是什么呢? 封装就是这个人要完成一件事情,他所需要的任何工具都带在了自己的身上,所需要的技术也都装在了自己的脑子里了。不需要借助于别人的力量就能完成这一件事情。这个有什么好处呢?好处就是如果我要吩咐这个人去完成一件事情,我不需要知道他是怎么完成的,也不需要协助他去完成,只要知道结果,他完成了就OK了。至于他是先干什么后干什么我不干涉,这有助于他更快更好的干好这件事情,我自己也省事。

1、访问权限(可见性)

Public:(随处可见)所有包、类导入后均可见  公共的

Protected:(合法继承)本身、不同包的子类自身,

Private:(自私自利)只在本类中可见

本类

同包类

public

protected

default

private

不同包类

public

protected

default

 

子类

子类

public

Protected(子类中,且子类自身使用)

 

 

其他类

public

 

 

 

 

2、

(1)、属性-->private(私有属性,公开方法,不用默认)

(2)、方法--> public    protected  

书面的解释如下: 每个对象都包含它能进行操作所需要的所有信息,因此对象不必依赖其它的对象来完成自己的操作。

二、继承: 还以为人为例,我们每个人都会有一些共同的特征,都要做一些相同的事情。比如:人都有一个脑袋,二只胳膊,二条脚,这是共同的特征。都要吃饭,喝水,这是都要做的相同的事情。那么如果我们现在要声明很多个人,每个人都会有这些特征,那我不是要写很多重复的代码?所以我们可以先建一个人的父类,这个父类不代表一个具体的人,只是一个拥有人所有共同特性的虚拟的人。下次我 们要实例化一个具体的人的时候,只需要将这个人继承上面这个“虚拟的人”,那么他就拥有了人的所有共同特性。这样,这些重复的代码我们就可以不写了。

当然,继承的目标不仅仅是为了节省代码,还有实现后面的多态的功能。初学者只需要了解继承可以少写很多代码就好了,余下的需要在项目中慢慢理解。

书面的解释如下: 对象的继承代表一种"is-a"的关系,假如两个对象A和B,如果可以描述为"B就是A",那么则表示B可以继承自A。

注意: 如果A继承了B,那么A不仅拥有了B除私有的特性外的所有特性,A还可以拥有自己独特的特性。比如上面人的这个例子,一个继承了 “虚拟的人”,那么他除了有一个脑袋,二只胳膊,二条脚,要吃饭喝水外,他可能还会编程。编程就是他独特的特性了,因为不是每个人都会编程的。

1、

(1)、延续:父类存在,子类没有重写但可以使用;

(2)、新增:父类没有,子类新增加的

(3)、重写:父类子类都存在,但是弗雷德不满足要,子类对其进行从新定义;

2、 实例化:

      (1)、先父类后子类,先静态后成员;

           实例化的时候先调用父类的静态构造快,在调用父类的构造方法,然后子类的构造块,在调用子类的构造方法;

(2)、默认调用父类空构造;

3、重写  override

      (1)、重写与重载:

           重写:继承的子类中,方法签名相同( 方法名+形参个数 类型 顺序  )

           重载:同一个类 方法名相同 ,形参个数 类型 顺序 不同

      (2)、重写规则:在子类中签名与父类中相同,在合理范围内提高子类可见性;

         A、返回类型:基本类型和void必须相同;引用类型要<=父类的返回类

         B、异常:

         C、可见性:要大于或等于父类中被重写的方法

三、多态: 有多态之前必须要有继承,只有多个类同时继承了同一个类,才有多态这样的说法。

还是以人为例子,前面我们有说过人都要做“吃饭”这样一个相同的事情。“吃饭”这个事情,体现到类中就是方法了。因为是人都是要做的,所以我们在“虚拟的人”中写好了这个方法,但每个人都有不同的吃饭方法,有用筷的也有用叉的,有要吃米饭的也有要吃面食的。所以如果我们要描述不同人的吃饭的过程,就要把这个过程放到具体的子类中去了,因为每个人都不一样嘛。同样一个方法,子类都有不同的实现方式,这个就是多态了,多态有助于程序的灵活性。

注意:子类中如果重写了父类的方法(多态),那么父类中的这个方法将不会再调用。

1.好处:

简化了编程接口。它容许在类和类之间重用一些习惯性的命名,而不用 为每一个新加的函数命名一个新名字。

简化代码

如果函数/方法参数中使用的是父类的类型,可以传入父类、子类的对象

局限性:父类类型的变量,不能直接调用子类特有的方法。必须强转为子类类型的变量,才能直接调用子类特有的方法

2、编译时多态:其实就是重载,是对非虚成员来说的,系统在编译时,根据不同签名来决定实现何种操作。

3、运行时多态:也就是重写,是通过虚成员实现的,指直到系统运行时,才根据实际情况决定实现何种操作。

对与第一种情况很容易就能理解,不同签名就有不同的实现

而第二种情况是在继承的基础上实现的,子类继承基类时,通过对虚成员的重写,然后利用基类引用子类对象,那么不同的子类对象实现相应的不同操作。

这样的好处是显而易见的,利用基类类型定义一次,然后给它传入不同的子类对象,然后实现不同的操作,提高了效率。

2018-04-28 17:32:23 qq_35335038 阅读数 47
1、封装:将变量和对变量的所有操作都封装在一个集合中,并将内部数据隐藏起来,从而提高内部数据的安全性
2、派生类直接使用基类定义好的字段和方法,从而实现代码的复用。
(1)、继承后的派生类将获得除了构造函数和析构函数以外的所有成员。
(2)、静态类不能被继承。
(3)、基类的私有成员,派生类不能直接访问。
 1)、派生类通过基类的公有方法或属性来访问基类的私有成员。
 2)、将基类中的私有(private)成员改为(protected)保护成员。
(4)、派生类的构造函数:
eg、
class A
{
protected int a;
public A(int _a)
{
a = _a;
}
}
class B:A
{
private int b;
//在派生类的构造中显式地调用基类的构造方法
//初始化派生类继承自基类的字段
public B(int _a,int _b):base (_a)
{
//a = _a;
//在派生类的构造函数中也可以给基类的字段赋值,但一般不要这样写。
b = _b;
}
public void print()
{
Console.WriteLine ("a={0},b={1}", a, b);
}
}
3、多态:用基类对象来统一来操作各种派生类的对象,基类对象有多种表现形态,用基类对象调用到派生类版本的函数。
(1)、方法重写:派生类可以直接使用继承下来的方法,被重写的方法在基类中必须是虚方法(即有virtual关键字)。在派生类中重写必须加override关键字。
如果派生类中重写方法时,把override关键字换成了new关键字,则中断基类对象的调用。
eg、
class Father
{
public virtual void print()
{
Console.WriteLine ("I am 123");
}
}
class BigSon:Father
{
public override void print()
{
Console.WriteLine ("I am 1");
}
}
class SamllSon:Father
{
public new void print()
{
Console.WriteLine ("I am 2");
}
}
class MainClass
{
public static void Main()
{
Father f = new BigSon ();
f.print ();
//基类中是virtual,派生类中是override关键字时,基类调用的是派生类里的方法
f = new SamllSon ();
f.print ();
//派生类中是new关键字时,基类调用的是基类里的方法,调不到派生类里的方法
}
}
输出结果为:I am 1
 I am 123
(2)、密封类:不能被继承的类
密封类强行继承会产生编译错误。
(3)、密封方法:派生类可以通过将其重写的方法声明为sealed来停止后面的派生类实现的虚拟继承。
父类A,B继承A,C继承B,A中方法为virtual,B中(override)重写方法,C中再用(override)重写方法。把B中的重写方法前加上(sealed关键字,B中方法就为密封方法,C中不能在次重写了。
eg、
class A
{
public virtual void Work() {}
}
class B:A
{
public sealed override void Work() {}
}
class C:B
{
public override void Work() {}//因为B中Work方法是密封方法,故而C中不能重写该方法
}
Note:
1)密封类中不一定有密封方法;
2)密封方法不一定在密封类中;
(4)、抽象类:不能实例化的类,即不能声明抽象类的对象。因此抽象类只能作为基类存在。用abstruct。
(5)、抽象方法:只能声明,不能实现,只能在派生类中实现。
Note:
1)抽象方法:为不同种类的子类对象提供了一个统一的接口
2)基类中抽象方法不需要加virtual,就能在子类中被重写。
3)派生类一定要实现抽象类中,所有抽象方法的重写,否则,该派生类会默认继承抽象方法,从而变成抽象类(没有存在的意义)。
4)抽象方法一定在抽象类中,抽象类中的方法不一定是抽象方法。


Note:密封类与抽象类的区别:
1、密封类只能实例化,不能继承;
2、抽象类只能继承,不能实例化;
(6)、在C#中,所有类都默认继承于Object类。故而在类中写ToString()方法时,必须加override重写。
ToString()方法在Object类中是虚方法(含有virtual关键字)。

面向对象三大特性 之 多态(C#)

阅读数 16

面向对象三大特性之多态(C#)今天和勇霞在路上走着讨论了一个问题,什么是"多态".通过讨论得出一个令人震惊的结论,那就是"多态我真的不懂你".学习过程中最大的悲哀莫过于明明是不懂却始终觉得自己很清楚,很明白,我理解,我懂得.很庆幸,因为知道了还不懂多态,接下来必然发生的事情就是我会真正的懂得.哈哈!!什么是多态?"多态"一词最早出现在生物学上,生物学的例子解释多...

博文 来自: iteye_3619

C#面向对象三大特性(重要)

阅读数 34

转载该博主很多文章都比较不错想要学好面向对象编程,除了掌握语法结构外最重要的就是熟悉面向对象三大特性,这三大特性不是相互独立的而是相互关联、你中有我我中有你的关系,想要真正了解三大特性必须把这三部分当做一个整体来考虑。封装封装就是通过给类及类中的成员变量、属性和方法设置不同的访问修饰符(public、protected、internal、protectedinternal、private)...

博文 来自: weixin_40333655

c#面向对象的三大特性之封装

阅读数 53

博文 来自: qq_40408661

C#面向对象三大特性总结

阅读数 1016

前言看完视频并没有及时总结,等到快要验项目了,才来又总结一遍。不过学习什么时候都不晚!其实看完设计模式以后对封装,继承,多态有了更深的理解。三大特性分别有封装,继承,多态封装字面意思也很好理解。我们大家都喜欢网购,产品为了不受破坏或者不外泄,都会进行产品封装,如果放到代码里,这就叫封装了。比如我们大家都玩微信,微信上面只有一些按钮来满足我们的需求,我们点击发送,消息就可以传...

博文 来自: Carrie_Q

面向对象三大特性 之 多态(C#)

阅读数 2252

面向对象三大特性之多态(C#)      今天和勇霞在路上走着讨论了一个问题,什么是"多态".通过讨论得出一个令人震惊的结论,那就是"多态我真的不懂你".学习过程中最大的悲哀莫过于明明是不懂却始终觉得自己很清楚,很明白,我理解,我懂得.很庆幸,因为知道了还不懂多态,接下来必然发生的事情就是我会真正的懂得.哈哈!!      什么是多态?      "多态"一词最早出现

博文 来自: bemavery
没有更多推荐了,返回首页