オブジェクト指向: 特殊なクラス

静的クラス(static/Shared)

クラス定義部分に直接アクセスし、インスタンス化時に作成(複写)されない。
静的クラス、静的インスタンス変数、静的メソッドがある。
スタティック領域にデータがあり、クラスから作成した複数のインスタンスで値を共有できる。

class MyClass:
 def normal_method:

 @staticmethod
 def static_method:

実行
MyClass.static_method()

public class NormalClass
{
  public int member { set; get; }
  public void Action() { }
}

public class StaticMember
{
  public static int member { set; get; }
  public static void Action() { }
}

public static class StaticClass
{
  public static int member { set; get; }
  public static void Action() { }
}

public void main()
{  
  NormalClass normalClass = new NormalClass();
  normalClass.member = 10;
  normalClass.Action();

  //↓インスタンス無しでクラスを利用できる
  StaticMember.member = 10;
  StaticMember.Action();
  StaticMember myMenber = new StaticMember();

  //↓エラー。インスタンスを作成できない。
  StaticClass myStatic = new StaticClass();
  myStatic.member = 10;
  myStatic.Action();

  //↓OK。
  StaticClass.member = 10;
  StaticClass.Action();
}

class MyClass
{
private:
 static int myStaInt;
public:
 MyClass();
 static int fnStaFunc();
};

MyClass::MyClass()
{
 this->myStaInt += 1;
 return;
}
static int MyClass::fnStaFunc()
{
 静的メソッド内でthis(インスタンスを表す)を使用できない。
 this->myStaInt += 10;
 
 myStaInt += 10;
 return myStaInt;
};

int MyClass::myStaInt = 0;

int _tmain(int argc, _TCHAR* argv[])
{

 int ret = 0;
 ret = MyClass::fnStaFunc();
 ret:10(myStaInt:10)
 MyClass *myClass1 = new MyClass();
 myStaInt:11
 MyClass *myClass2 = new MyClass();
 myStaInt:12
 MyClass *myClass3 = new MyClass();
 myStaInt:13
 ret = MyClass::fnStaFunc();
 ret:23(myStaInt:23)
 
 return 0;
}

Public Class NormalClass
  Private _member As Integer
  Public Property member As Integer
    略
  End Property
  Public Sub Action()
   ~
  End Sub
End Class

Public Class SharedMember
  Private Shared _member As Integer
  Public Shared Property member As Integer
    略
  End Property
  Public Shared Sub Action()
  ~
  End Sub
End Class

‘↓エラー
Public Shared Class SharedClass
 ~
End Class

Public Sub myForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load

  Dim myNormal As New NormalClass()
  myNormal.member = 10
  myNormal.Action()

  ‘インスタンス無しでクラスを利用できる。
  SharedMember.member = 10
  SharedMember.Action()
  Dim myMember As New SharedMember()
End Sub

public class SubClass {
  private int instanceMember;
  private static int staticMember;
  public void instanceMethod()
  {
    System.out.println(instanceMember);
  }
  
  static public int staticMethod1()
  {
    return staticMember;
  }
  
  static public int staticMethod2()
  {
    return instanceMember;
    ⇒ エラー。
    スタティックメソッドはインスタンス変数にはアクセスできない。
    this.instanceMember、this.staticMemberも×
    thisはインスタンスを指す為、静的メソッド内では使用禁止
  }
}

public class MyClass {
  public static void main(String[] args) {
    
    SubClass sub = new SubClass();
    sub.instanceMethod();

    
    //インスタンスを作成せず、直接staticメソッドを実行
    SubClass.staticMember = 5;
    int ret1 = SubClass.staticMethod1();
    
    //インスタンスを作成せず、直接staticメソッドを実行
    int ret2 = SubClass.staticMethod2();

  }
}

MyClass::$myVal = “aaa”;
print(MyClass::$myVal);
→aaa

MyClass::Method();
静的メソッド呼び出し時は「$」は付けない
→aaa

public class MyClass{
 public static $myVal;
 
 public static function Method(){
  print(“aaa”);
 }
}

MyClass::Method();
→aaa

class MyClass{
 private static $_myVal;
 
 public static function GetValue()
 {
  return self::$_myVal;
 }
 
 public static function Method(){
  静的メソッド内からクラス内静的プロパティを呼び出し
  self::$_myVal = “aaa”;
  
  静的メソッド内からクラス内静的メソッドを呼び出し
  print(self::GetValue());
  静的メソッド呼び出し時は「$」は付けない
 }
}

self::とstatic::
class ParentClass
{
 public static function static_method() {
 echo ‘ParentClass’, PHP_EOL;
 }
 public function parent_method() {
   static::static_method();
   self::static_method();
 }
}

class ChildClass extends ParentClass
{
 public static function static_method() {
  echo ‘ChildClass’, PHP_EOL;
}
 public function child_method() {
  static::static_method();
  self::static_method();
 }
}

ParentClass::static_method();
→ ParentClass
ChildClass::static_method();
→ ChildClass

$parent = new ParentClass();
$parent->parent_method();
→ ParentClass
→ ParentClass

$child = new ChildClass();
$child->child_method();
→ ChildClass
→ ChildClass

$child = new ChildClass();
$child->parent_method();
→ ChildClass
※static::static_method()
「static::」=実行時のclass(ChildClass)が呼ばれる
→ ParentClass
※self::static_method();
「self::」=定義時のclass(ParentClass)が呼ばれる

拡張メソッド

静的クラスに作成する、宣言無く使用できるメソッド

public static class myExtension
{
 public static void myMethod(this string prm)
 {
  Console.WriteLine(prm);
 }
}

myExtension.myMethod(@”aaa”);
→aaa

@”bbb”.myMethod();
→bbb
※拡張メソッドではクラス名を省略できる

LINQの拡張

LINQに関しては「LINQ」参照

class Person
{
 public int Id { get; set; }
 public string Name { get; set; }
}

class Persons : List<Person> { }

static class PersonExtension
{
 Whereの拡張メソッド
 public static Persons Where(this Persons self, Func<Person, bool> predicate)
 {
  var result = new Persons();
  foreach (var p in self)
  {
   if (predicate(p)) result.Add(item: p);
  }
  return result;
 }
}

class Program
{
 static void Main(string[] args)
 {

  var p = new Persons();
  p.Add(new Person() { Id = 1, Name = “C#” });
  p.Add(new Person() { Id = 2, Name = “VB.NET” });
  p.Add(new Person() { Id = 3, Name = “Java” });
  p.Add(new Person() { Id = 4, Name = “PHP” });
  
  IEnumerable.Whereでなく、拡張メソッドWhereを呼び出し
  var ary1 = p.Where(x => x.Id > 2).Select(x => x.Name).ToArray();
  
  IEnumerable.Whereを呼び出し
  var ary2 = p.AsEnumerable().Where(x => x.Id > 2).Select(x => x.Name).ToArray();
 }
}

ローカルクラス

public static void main(String[] args) {
 メソッド内でクラスを定義
 class Local {
  public void sayHello() {
   System.out.println(“HelloWorld”);
  }
 }
 ローカルクラスのメソッドを実行
 new Local().sayHello();
}

public static void main(String[] args) {
 メソッド内でインターフェースを実装したクラスを定義
 class Local implements Runnable {
  @Override
  public void run() {
   System.out.println(“HelloLambda”);
  }
 }
 ローカルクラスのメソッドを実行
 new Local().run();
}

匿名クラス

//Setプロパティのない、クラス内部をプログラマーが見れないクラスを作成
var anonymous = new { Name = “Yone”, Age = 35 };
Console.WriteLine(value: anonymous.Name + “(” + anonymous.Age + “)”);
⇒ Yone(35)

ASP.NET MVC ビューヘルパー(「ASP.NET MVC HTMLヘルパー」参照)、やLINQtoEntity(「LINQtoEntity」参照)で利用する

//Writeプロパティのない、クラス内部をプログラマーが見れないクラスを作成
Dim anonymous = New With { .Name = “Yone” , .Age = 35 }
Console.WriteLine(value:=anonymous.Name & “(” & anonymous.Age & “)”)
⇒ Yone(35)
実在のクラスしかインスタンス化できない
public void method(){
 Thread c = new Thread(){
  public void run(){System.out.println(“thread start”);}
 };
 c.run();
 
 インスタンス化と同時に実行
 new Thread(){
  public void run(){System.out.println(“thread start”);}
 }.run();
}

public void method(){
 new A(){
  public void run(){System.out.println(“thread start”);}
 }.run();
 エラー:クラスAが無いから
 
 ローカルクラス
 class A{};
 
 new A(){
  public void run(){System.out.println(“thread start”);}
 }.run();
 OK
}

インターフェースを実装したローカルクラスを省略形で定義
public static void main(String[] args) {
 メソッド内でインターフェースを実装したローカルクラスを定義 ※省略形
 Runnable run = new Runnable() {
  @Override
  public void run() {
   System.out.println(“Hello Lambda”);
  }
 };
 メソッド内でインターフェースを実装したローカルクラスを実行
 run.run();
}

インターフェースを実装したローカルクラスをラムダ式で定義
Runnable run = () -> { System.out.println(“Hello Lambda”); };
run.run();

ラムダ式については「プログラム言語 ラムダ式」参照

フレンドクラス/フレンド関数

フレンドクラス
class MyClass{
private:
 int myInt;
public:
 MyClass(int prm){ this->myInt = prm; };
 
 MyFriendには自身のインスタンス変数へのアクセスを許可
 friend class MyFriend;
};

class MyFriend
{
public:
 int Get(MyClass prmClass)
 {
  本来アクセスできないMyClassのインスタンス変数にアクセスする
  return prmClass.myInt;
 }
};

int _tmain(int argc, _TCHAR* argv[])
{

 MyClass myClass(5);
 
 フレンドクラスであるMyFriendは、
 本来アクセスできないMyClassのインスタンス変数にアクセスできる

 int ret = (new MyFriend->Get(myClass) ;
 ret:5
 
 return 0;
}

フレンド関数
class MyClass{
private:
 int myInt;
public:
 MyClass(int prm){ this->myInt = prm; };
 friend int Get();
 friend int Get(MyClass m);
};

int Get()
{
 return 5;
}

int Get(MyClass m)
{
 return m.myInt;
}

int _tmain(int argc, _TCHAR* argv[])
{

 int ret;
 MyClass *myClass = new MyClass(10);
 
 ret = Get();
 ret:5
 
 本来アクセスできないMyClassのインスタンス変数にアクセスできる
 ret = Get(*myClass);
 ret:10
 
 return 0;
}

メンバークラス/ローカルクラス
メンバクラス
public class Test {
 public void method(){
  Child c = new Child();
  c.method();
 }
 private class Child extends Test{
  public void method(){System.out.println(“inner”);}
 }
}

ローカルクラス
public void method(){
 class Child{
  private void method(){System.out.println(“local”);}
 }
 Child c = new Child();
 c.method();
}

仮想基本クラス

同一の基底クラスを継承した派生クラスを多重継承した場合に、
基底クラスのメンバーを派生クラスにおいて重複して継承してしまう問題を回避する為のクラス
多重継承については「オブジェクト指向: 継承/多重継承」参照

※基底クラス
class Parent
{
protected:
 int myIntP;
public:
 Parent(int prm = 10){ this->myIntP = prm; };
 virtual void ShowData() = 0;
};

※派生クラス1
通常継承
class Child1 : public Parent

基底クラスを仮想基本クラスとして継承
class Child1 : public virtual Parent
{
public:
 Child1(int prm = 20){ this->myIntP = prm; };
 void ShowData();
};

void Child1::ShowData()
{
 std::cout << this->myIntP << ‘\n’;
}

※派生クラス2
通常継承
class Child2 : public Parent

基底クラスを仮想基本クラスとして継承
class Child2 : public virtual Parent
{
public:
 Child2(int prm = 30){ this->myIntP = prm; };
 void ShowData();
};

void Child2::ShowData()
{
 std::cout << this->myIntP << ‘\n’;
}

※派生クラス1、2を多重継承
class GrandChild : public Child1, public Child2
{
public:
 通常継承時
 GrandChild(int prm = 40){ this->myIntP = prm; };
 ※コンパイルエラー:myIntPはChild1、Child2の両方にあるので曖昧
 
 基底クラスを仮想基本クラスとして継承した場合
 GrandChild(int prm = 40){ this->myIntP = prm; };
 ※OK:myIntPは基底クラスを参照する。
 
 void ShowData();
};

void GrandChild::ShowData()
{
 通常継承時
 std::cout << this->myIntP << ‘\n’;
 ※コンパイルエラー:myIntPはChild1、Child2の両方にあるので曖昧
 
 基底クラスを仮想基本クラスとして継承した場合
 std::cout << this->myIntP << ‘\n’;
 ※OK:myIntPは基底クラスを参照する。
 
}