[C#]——接口与继承

一、. 接口 interface ------ C++ 纯虚基类的「升级版」

C++ 里你想要「只定规矩、不定实现」会用纯虚基类:

复制代码
// C++:纯虚基类 = 接口
class Ishape
{
public:
    virtual ~Ishape() = default;  //c++习惯:虚析构
    virtual double Area() const= 0;    // 纯虚函数 = 0
    virtual void Print() const= 0;    
}


//c#interface 自带【抽象】属性,不用写virtual 、不用=0
Interface   Ishape
{
 public:
     double Area();      //默认抽象,分号结尾
     void Print();    
}

1.1 C++ vs C# 对照表

|----------|--------------------------|----------------------|
| 维度 | C++ 纯虚基类 | C# interface |
| 关键字 | class + = 0 | interface(独立关键字) |
| 成员默认 | 普通函数,需手写 virtual ... = 0 | 自动抽象,不写 virtual |
| 访问修饰 | 自己写 public: | 一律 public,不能写 public |
| 字段(数据成员) | 可以有 | 不能有(只能有方法/属性/事件) |
| 多继承 | 可以,但容易钻石继承 | 类可实现多个接口,天然解冲突 |
| 虚析构 | 必须手写 virtual ~Foo() | 不需要(C# 有 GC,没这坑) |

1.2 三个关键规则(C# 特有,C++ 没有的约定)

1、接口名约定用 I 开头:IShape、IDrawable、IComparable。这是 .NET 的硬约定,C++ 没这规矩。

2、接口里不能写字段,但可以写「属性」------属性本质是方法嘛:

interface IAnimal

{

string Name { get; set; } // ✅ 属性,本质是两个方法 get_/set_

// int age; // ❌ 编译错误,接口不能有字段

}

3、类可以实现多个接口(这是 C# 比 C++ 多继承更优雅的地方,后面练习会演示)。


二、继承语法 : ------ C# 用一个冒号通吃

C++ 继承要写访问修饰:class Dog : public Animal。

C# 不用,一个冒号搞定,因为 C# 只有 public 继承(没有 private/protected 继承那套)。

复制代码
//c++
class Cricle : public Ishape{};

//c# --冒号后面直接跟基类/接口
class Cricle : Ishape{}             //实现接口
class Dog : Animal{}                //继承类
class Bagle :Animal,IFlyable,IComparable{}     //一个基类 + 多个接口

⚠️ 规则:基类只能有一个(C# 不允许多继承类),接口可以有任意多个。基类要写在最前面。

调用基类构造:base(...) ≈ C++ 的 Base(...)

复制代码
// C++:初始化列表调基类构造
class Dog : public Animal {
public:
    Dog(string n) : Animal(string n)       //基类构造
};


// C#:base(...) 相当于 C++ 初始化列表
// C++:初始化列表调基类构造
class Dog : Animal {

  public  Dog(string n) : base(string n)       //调用animal的构造函数
};

三、 is / as ------ C# 版的 dynamic_cast

这是 C++ 转 C# 最容易对应上的点。C++ 你用 dynamic_cast 做运行时类型转换:

复制代码
// C++:dynamic_cast

IShape* s = new Circle(2);
Circle* c = dynamic_cast<Circle*>(s); // 失败返回nullptr
if(dynamic_cast<Rectangle*>(s))       // 判断是不是某个类型
{

}

C# 拆成两个更直观的关键字:

|-----------------------------------|--------|--------------------------|
| C++ | C# | 干什么 |
| dynamic_cast<T*>(p) != nullptr | p is T | 判断:是不是这个类型,返回 bool |
| dynamic_cast<T*>(p) | p as T | 转换:能转就给对象,不能转给 null(不抛异常 |

复制代码
// C++ as
Ishape s = new Cricle(2);
if(s is Rectangle){}                   //false
Circle c = s as Cricle;                // 成功->Circle对象
Rectangle r = s as Rectangle;          // 失败 → null,不崩

小提示:C# 7+ 还有个更顺手的 if (s is Circle c) ------判断+转换+变量名一步到位,后面练习里我会用到。

复制代码
using System;
using System.Collections.Generic;


interface IShapes
{
    double Area();
    void Print();
}

interface IDrawable
{
    void Draw();
}


class Circle : IShapes, IDrawable        // 冒号 + 接口列表,一个类实现多个接口
{
    public double Radius { get; }
    public Circle(double radius)
    {
        Radius = radius;
    }
    public double Area() => 3.14 * Radius * Radius;
    public void Print() => Console.WriteLine($"圆的半径 ={Radius}面积={Area():F2}");
    public void Draw() => Console.WriteLine($"  画一个圆 ○ (半径 {Radius})");

}
class Rectangle : IShapes                // 只实现 IShape
{
    public double width { get; }
    public double Length { get; }

    public Rectangle(double w, double h)
    {
        width = w;
        Length = h;
    }
    public double Area() =>  width * Length;
    public void Print() => Console.WriteLine($"矩形长宽 ={width}x{Length} 面积={Area():F2}");
}

class Animal
{
    public string Name { get; }
    public Animal(string name) => Name = name;
    public virtual void Speak() => Console.WriteLine($"{Name}: ...");
}

class Dog : Animal
{
    public Dog(string name) : base(name) { }   // base(...) ≈ C++ 初始化列表
    public  override void Speak()=> Console.WriteLine($"{Name}: DOGDOG");
}
class Program
{
    static void Main()
    {
        // 用接口类型装具体对象 ------ 这就是多态的雏形
        // C++ 等价:vector<IShape*> shapes;
        List<IShapes> shapes = new()
        {
            new Circle(3),
            new Rectangle(4, 5),
            new Circle(1),
            new Rectangle(2, 3)
        };

        Console.WriteLine("===== 所有图形 =====");
        double total = 0;
        foreach(var s in shapes)
        {
            s.Print();
            total += s.Area();
        }
        Console.WriteLine($"面积={total:F2}");


        // is / as:把圆单独挑出来(≈ C++ dynamic_cast)
        Console.WriteLine("===== 挑出圆,打印半径 =====");
        foreach(var s in shapes)
        {
            if(s is Circle c)
            {
                Console.WriteLine($"招到圆,圆的半径={c.Radius}");
                c.Draw();                // 圆实现了 IDrawable,可以调
            }
        }


        //as 用法
        Console.WriteLine();
        IShapes first = shapes[0];
        Rectangle r = first as Rectangle;
         // 继承 demo
        Console.WriteLine("\n===== 继承 demo =====");
        Animal a = new Dog("wangcai");
        a.Speak();
    }
}
相关推荐
xiaoye-duck12 分钟前
《C++ 项目:手写大模型接入 SDK》Ollama接口设计(上):初始化、全量响应实现和测试
开发语言·网络·c++·语言模型
zaizai10071 小时前
【Effective Modern C++】学习第一章
c++
Fruiticecake1 小时前
C 程序员速通现代 C++(一):lambda、std::function、移动语义与智能指针
c语言·c++
总要学点什么1 小时前
第98篇:三维特效-材质线效果——给一条线换十种材质,虚线的图案只填了一半
开发语言·前端·javascript·ecmascript·gis·webgl·材质
田甲2 小时前
做一款 Type-C 母座读卡器:GL3224 双卡方案实测
c语言·开发语言
青少儿编程课堂2 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:中缀表达式求值解析
c++·python·算法·bfs·信息学竞赛
严肃小白兔2 小时前
MATLAB 绘图与科研论文插图制作:图形设计、统计表达与矢量导出
开发语言·matlab·科研绘图
Funlang4 小时前
给机器写的 JavaScript 造个笼子
开发语言·javascript·ecmascript
普通人64 小时前
PHP文件读写完全指南
开发语言·php·1024程序员节
坤坤子吖4 小时前
Linux网络编程:TCP服务器的多进程与多线程实现
linux·服务器·开发语言·网络·c++·笔记·学习