接口,抽象类使用案例 - 1

66 阅读2分钟

前言:有时候会混合使用抽象类与接口,分不清什么时候使用抽象类,什么时候使用接口。

一般来说,抽象类为继承体系表示继承关系,接口为层次体系表示能力。

 实现:炊事员与陆军都属于部队,但陆军会开枪,猎人也会。所以将陆军与炊事员抽象出士兵类,开枪的能力抽象出接口。

CPP:

士兵类:

enum RANK
{
	OR_1,
	OR_2,
};
class SolidersBase
{
public:

	SolidersBase(RANK rank) :rank(rank) {}
	virtual RANK GetRank() = 0;
protected:
	RANK rank;

};

开枪接口:

class IShooting
{
public:
	virtual void Shooting() = 0;
};

派生类实现:

class Army :public SolidersBase, public IShooting 
{
public:
	Army(RANK r) :SolidersBase(r) {}
	RANK GetRank() override { return rank; }
	void Shooting() override { std::cout << "Solider shoot" << std::endl; }
};

class Cook :public SolidersBase
{
public:
	Cook(RANK r) :SolidersBase(r) {}
	RANK GetRank() override { return rank; }

};

class Hunter :public IShooting
{
public:
	void Shooting() override {
		std::cout << "Hunter shoot" << std::endl;
	}

};

调用:

	SolidersBase* solider1 = new Cook(RANK::OR_1);
	SolidersBase* solider2 = new Army(RANK::OR_2);
	Hunter hunter;

	std::cout << "solider1:" << solider1->GetRank() << "; " << "solider2:" << solider2->GetRank() << std::endl;
	SomeOneShoot(&hunter);
	SomeOneShoot((IShooting*)(Army*)(solider2));
	if (auto* ifun = dynamic_cast<IShooting*>(solider1))
		SomeOneShoot(ifun);
	else
	{
		std::cout << "don't know shooting" << std::endl;
	}
	if (auto* ifun = dynamic_cast<IShooting*>(solider2))
		SomeOneShoot(ifun);
	else
	{
		std::cout << "don't know shooting" << std::endl;
	}

注意:

调用时需要先转到继承了接口的类,再转接口。不然会出现虚函数调用错误问题(调用的不是想要调用的虚函数)。

或者使用dynamic_cast进行转换。

C#:C#有接口不会出现CPP虚表偏移的情况:

实现:

  /// <summary>
  /// 等级
  /// </summary>
  enum RANK
  {
      OR_1,
      OR_2,
  };


  abstract class SolidersBase
  {
      protected RANK rank;

      public SolidersBase(RANK rank)
      {
          this.rank = rank;
      }

      public abstract RANK GetRank();
  }

  /// <summary>
  /// 炊事员
  /// </summary>
  class Cook : SolidersBase
  {
      public Cook(RANK rank)
          : base(rank) { }

      public override RANK GetRank()
      {
          return rank;
      }
  }

  /// <summary>
  /// 陆军
  /// </summary>
  class Army : SolidersBase, IShooting
  {
      public Army(RANK rank)
          : base(rank) { }

      public override RANK GetRank()
      {
          return rank;
      }

      public void Shooting()
      {
          Console.WriteLine("Solider shoot");
      }
  }

  /// <summary>
  /// 开枪
  /// </summary>
  interface IShooting
  {
      public void Shooting();
  }

  class Hunter : IShooting
  {
      public void Shooting()
      {
          Console.WriteLine("Hunter shoot");
      }
  }

  static class ShootHelper
  {
      public static void SomeOneShoot(IShooting shooter)
      {
          shooter.Shooting();
      }
  }

调用:

     SolidersBase solider1 = new Cook(RANK.OR_1);
     SolidersBase solider2 = new Army(RANK.OR_2);

     Hunter hunter = new();
     ShootHelper.SomeOneShoot(hunter);
     ShootHelper.SomeOneShoot((IShooting)solider2);
     if (solider1 is IShooting shooter1)
         ShootHelper.SomeOneShoot(shooter1);
     else
     {
         Console.WriteLine("don't know shooting");
     }
     if (solider2 is IShooting shooter2)
         ShootHelper.SomeOneShoot(shooter2);
     else
     {
         Console.WriteLine("don't know shooting");
     }