オブジェクト指向: コンストラクタ
目次
コンストラクタ
通常
インスタンス作成時に呼び出されるメソッド
{
public int member { get; set; }
//コンストラクタ(クラス名と同じ)
public clsTest(int init)
{
this.member = init;
}
public void calc()
{ this.member += 10; }
}
public void main()
{
clsTest myClass = new clsTest(5);
myClass.calc();
⇒15
}
コンストラクタのオーバーロード(多重定義)も可能
(オブジェクト指向: プロパティ・メソッド/オーバーロード参照)
コンストラクタのあるクラスを継承した場合
「継承時のコンストラクタ」参照
{
private:
~;
public:
MyClass();
};
MyClass::MyClass()
{
※ここが処理される
~
};
int main(array<System::String ^> ^args)
{
MyClass *myClass = new MyClass();
myClass->~;
delete myClass;
return 0;
}
Private _member As Integer
’コンストラクタ
Public Sub New(ByVal init As Integer)
me._member = init
End Sub
Public Sub Calc()
_member += 5
End Sub
End Class
Sub main()
Dim myTest As New clsTest(5)
Call myTest.Calc()
⇒10
End Sub
コンストラクタのあるクラスを継承した場合
「継承時のコンストラクタ」参照
int member;
//コンストラクタ
MyClass(){
this.member = 0;
}
//コンストラクタのオーバーロード
MyClass(int prm){
this.member = prm;
}
}
public static void TEST( ~ ){
MyClass myclass = new MyClass();
⇒myclass.member : 0;
MyClass myclass = new MyClass(10);
⇒myclass.member : 10;
}
//コンストラクタ
this.member1 = prm1;
this.member2 = prm2;
this.Add = function(){
return this.member1 + this.member2;
};
}
var number = new Calc1(1, 2);
var x = number.Add();
⇒x = 3
$p->Method();
->aaa
class MyClass{
private $_myVal;
function __construct($prm)
{
$this->SetMyVal($prm);
}
function SetMyVal($prm)
{
$this->_myVal = $prm;
}
function Method(){
print($this->_myVal);
}
}
デフォルトコンストラクタ
コンストラクタを定義しなかった場合に、
コンパイラによって自動的に作成されるコンストラクタ
引数及び処理内容無し。
同一クラス内からのコンストラクタ呼び出し
共通の処理をprivateのメソッドとして定義しておき、それを呼び出す方法がある。
// ①
public MyClass(){
~
}
// ②
public MyClass(int prm){
※引数無しコンストラクタ①の呼び出し
this();
}
}
public class Base {
public static void main(String[] args) {
※引数有りコンストラクタ②の呼び出し
MyClass m = new MyClass(5);
}
}
呼び出し処理の記述順
class MyClass{
public MyClass(){
~
}
public MyClass(int prm){
System.out.println(“test”);
this(); //コンパイルエラー
※コンストラクタの呼び出しは最初に行わなければならない
}
public MyClass(int prm){
this(); // OK
System.out.println(“test”);
}
}
明示的に呼び出す必要あり
class classP
{
public function __construct(){
~
}
}
class classC extends classP
{
public function __construct(){
parent::__construct();
~
}
}
初期化ブロック
public MyClass()
{
System.out.println("A");
}
※コンストラクタ実行前に呼び出される
{
System.out.println("B");
}
}
public class Base {
public static void main(String[] args) {
MyClass m = new MyClass();
}
}
⇒ B A
初期化ブロックの記述パターン
以下、全てOK。 記述位置に関わらず全てコンストラクタの実行前に実行される。
public class MyClass {
{
// コンストラクタの前
}
public MyClass(){}
}
public class MyClass {
public MyClass(){}
{
// コンストラクタの後
}
}
public class MyClass {
{
// コンストラクタ無し
}
}
引数無しコンストラクタを明示的に定義しないクラスを継承した場合のコンストラクタ呼び出し
abstract class Super{
※引数無しコンストラクタは定義されていない
Super(int prm){}
}
class Sub extends Super{
※引数有りコンストラクタを呼び出す必要がある。
Sub(int prm){
super(prm);
これはスーパークラスのコントストラクタを呼び出すという意味。
「Super」クラスのクラス名ではない
}
※↓ はNG。
Sub(){
super();
}
※↓ も当然NG。スーパークラスのコンストラクタを呼び出す必要がある。
Sub(){}
}
継承時のコンストラクタ
{
public string name { set; get; }
public int age { set; get; }
public Parent(string prmName, int prmAge)
{
this.name = prmName;
this.age = prmAge;
}
}
public class Child : Parent
{
public string parentname { set; get; }
public Child(string prmName, int prmAge) : base(prmName, prmAge)
{
this.parentname = base.name;
}
}
public void myForm_Load(object sender, EventArgs e)
{
Child child = new Child(prmName: "parent1", prmAge: 5);
⇒child.name = "parent1"
⇒child.age = 5
⇒child.parentname = "parent1"
}
{
private:
int myInt1;
int myInt2;
public:
MyParent(int prm1, int prm2);
int GetMyInt1();
int GetMyInt2();
};
MyParent::MyParent(int prm1, int prm2)
{
this->myInt1 = prm1;
this->myInt2 = prm2;
return;
}
int MyParent::GetMyInt1()
{
return this->myInt1;
}
int MyParent::GetMyInt2()
{
return this->myInt2;
}
class MyChild : public MyParent
{
private:
int myInt1;
int myInt2;
public:
MyChild(int prm1, int prm2, int prm3, int prm4);
};
※親クラスのコンストラスタに渡す引数を子クラスの引数で引き取る
MyChild::MyChild(int prm1, int prm2, int prm3, int prm4) : MyParent(prm3, prm4)
{
this->myInt1 = prm1;
this->myInt2 = prm2;
return;
}
int _tmain(int argc, _TCHAR* argv[])
{
MyParent *myParent = new MyParent(1, 2);
cout << myParent->GetMyInt1() << '\n';
→1
cout << myParent->GetMyInt2() << '\n';
→2
MyChild *myChild = new MyChild(1, 2, 3, 4);
cout << myChild->GetMyInt1() << '\n';
→3
cout << myChild->GetMyInt2() << '\n';
→4
return 0;
}
Private _name As String
Private _age As Integer
Public Sub New(ByVal prmName As String, ByVal prmAge As Integer)
Me._name = prmName
Me._age = prmAge
End Sub
Public Property name As String
略
End Property
Public Property age As Integer
略
End Property
End Class
Public Class Child
Inherits Parent
Private parentname As String
Public Sub New(ByVal prmName As String, ByVal prmAge As Integer)
MyBase.New(prmName:=prmName, prmAge:=prmAge)
Me.parentname = MyBase.name
End Sub
End Class
Public Class myForm
Private Sub myForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim child As New Child(prmName:="parent1", prmAge:=5)
⇒child.name = "parent1"
⇒child.age = 5
⇒child.parentname = "parent1"
End Sub
End Class
int member;
//コンストラクタ
Parent(){
this.member = 0;
}
//コンストラクタのオーバーロード
Parent(int prm){
this.member = prm;
}
}
class Child extends Parent {
//コンストラクタ
基底クラスの引数無しコンストラクタが自動的に呼ばれる
Child(){}
//コンストラクタのオーバーロード
Child(int prm){
//明示的に別のコンストラクタを呼び出す場合
super(prm);
}
}
明示的に呼び出す必要あり
コピーコンストラクタ
関数へインスタンスを渡す際に実行されるコンストラクタ
通常は、コンストラクタは実行されない。
{
protected:
int myInt;
public:
MyClass(int prm = 0){
this->myInt = prm;
};
// コピーコンストラクタ
MyClass(const MyClass &m)
{
this->myInt = m.myInt + 1;
m.myInt:5
this->myInt:149405060
↓
this->myInt:6
};
int fnGet(){
return this->myInt;
};
};
int fnPlus(MyClass prmM);
int _tmain(int argc, _TCHAR* argv[])
{
MyClass m(5);
int ret;
ret = m.fnGet();
ret:5
ret = fnPlus(m);
ret:6
return 0;
}
このタイミングでコピーコンストラクタが実行される。
int fnPlus(MyClass m)
{
return m.fnGet();
}
コピーコンストラクタ実行のタイミング
MyClass m1(5);
int ret;
【初期化時(コピー)】
MyClass m2 = m1;
コピーコンストラクタが実行される
ret = m2.fnGet();
ret:6
ret = fnPlus(m2);
ret:7
【代入時(非コピー)】
m2 = m1;
コピーコンストラクタが実行されない
ret = m2.fnGet();
ret:5
ret = fnPlus(m2);
ret:6
コンストラクタのスコープ
アクセス修飾子としてpublic、protected、privateが利用可能
スコープはアクセス修飾子に従う。
class PubClass{
public PubClass(){}
}
class ProClass{
protected ProClass(){}
}
class PriClass{
private PriClass(){}
}
public static void main(String[] args) {
PubClass pub = new PubClass(); ⇒OK
ProClass pro = new ProClass(); ⇒OK
PriClass pri = new PriClass(); ⇒コンパイルエラー
}
静的ジェネリッククラスコンストラクタ
「プログラム言語 ジェネリック/静的ジェネリッククラスコンストラクタ」参照
デストラクタ
インスタンス破棄時に呼び出されるメソッド
多くの言語では明示的に呼び出すことはできない。
{
//コンストラクタ(クラス名と同じ)
public clsTest()
{ Console.WriteLine(2); }
public void method()
{ Console.WriteLine(3); }
//デストラクタ(「~」+クラス名)
~clsTest()
{ Console.WriteLine(5); }
}
static void Main(string[] args)
{
Console.WriteLine(1);
myFunc();
Console.WriteLine(4);
1,2,3,4,5か、1,2,3,5,4の順に出力される。
4が先か5が先か?はメモリの解放を司るOSの管理。
}
static private void myFunc()
{
clsTest test = new clsTest();
test.method();
}
{
public:
MyClass();
~MyClass();
};
MyClass::MyClass()
{
~
};
デストラクタ
MyClass::~MyClass()
{
インスタンスのdelete処理後に処理される
~;
}
int main(array<System::String ^> ^args)
{
MyClass *myClass = new MyClass();
myClass->~;
delete myClass;
return 0;
}
特にデストラクタが必要な場面
class MyClass{
private:
インスタンス変数をポインタで定義
int *ary;
public:
MyClass(int prm[]);
~MyClass();
int Get(int elmCnt);
};
MyClass::MyClass(int elm[])
{
ポインタにnewで作成した配列を格納
newで確保されたメモリ領域は明示的にdeleteしないと消えない
ary = new int[] { elm[0], elm[1], elm[2] };
}
MyClass::~MyClass()
{
delete ary;
}
int MyClass::Get(int elmCnt)
{
return this->ary[elmCnt];
}
int _tmain(int argc, _TCHAR* argv[])
{
int array[] = { 1, 2, 3 };
MyClass *m = new MyClass(array);
int ret = m->Get(2);
ret:3
delete m
return 0;
}
//デストラクタ
finalize(){
~
}
}
{
public function __destruct(){
~
}
}
class classC extends classP
{
public function __destruct(){
スーパークラスのデストラクタを明示的に呼び出す
parent::__destruct();
~
}
}
コピーコンストラクタ終了時の処理
{
public:
デフォルトコンストラクタ
MyClass()
{
cout << "デフォルト" << '\n';
}
コピーコンストラクタ
MyClass(const MyClass &prmClass)
{
cout << "コピー" << '\n';
}
デストラクタ
~MyClass()
{
cout << "デストラクタ" << '\n';
}
};
void myFunc(MyClass m)
{
cout << "サブルーチン" << '\n';
}
void myCall()
{
MyClass m;
myFunc(m);
}
int _tmain(int argc, _TCHAR* argv[])
{
myCall();
return 0;
}
結果
デフォルト
↓
コピー
サブルーチン開始時(インスタンスコピー時)にコピーコンストラクタが実行される
↓
サブルーチン
↓
デストラクタ
サブルーチン終了時(コピーインスタンス破棄時)にデストラクタが実行される
↓
デストラクタ
インスタンス破棄時にもデストラクタが実行される
明示的な開放処理
デストラクタ(の代わりの処理)の実行
{
public MyClass()
{
Console.Write(@"<p>");
}
public void Dispose()
{
Console.Write(@"</p>");
}
Disposeの実装が強制される
}
static void Main(string[] args)
{
using (var m = new MyClass())
{
Console.Write(@”Hello”);
}
}
結果:<p>Hello</p>
イニシャライザ
JAVA限定。
クラスファイルがロードされたタイミングで実行されるメソッド。
コンストラクタよりも早い。
//イニシャライザ
static{
~
}
//コンストラクタ
Foo{
~
}
}