Inheritance
9.1. การสืบทอด Inheritance
Inheritance คือการใช้ attributes และ method ของ Base class ซึ่งสามารถทำได้โดยเติมชื่อ Base class ไปหลังเครื่องหมาย ":" เช่น
class Derived: public Base{
...
};
โดยการกำหนดการเข้าถึงเป็น public จะทำให้การเข้าถึงใน base class ยังคงเหมือนเดิม
9.2. การเข้าถึง Access
- public: ทุกคนเข้าถึงได้
- private: เฉพาะ meber functions ในคลาสตัวเอง
- protected: เฉพาะ meber functions ในคลาสตัวเองและคลาสที่สืบทอด
| Access | public | protected | private |
|---|---|---|---|
| Same class | yes | yes | yes |
| Derived classes | yes | yes | no |
| Outside classes | yes | no | no |
class Base {
private:
int MyPrivateInt=1;
protected:
int MyProtectedInt=2;
public:
int MyPublicInt=3;
};
class Derived : public Base {
public:
int foo1() { return MyPrivateInt;} // Won't compile!
int foo2() { return MyProtectedInt;} // OK
int foo3() { return MyPublicInt;} // OK
};
class Unrelated {
private:
Base B;
public:
int foo1() { return B.MyPrivateInt;} // Won't compile!
int foo2() { return B.MyProtectedInt;} // Won't compile
int foo3() { return B.MyPublicInt;} // OK
};
output
derived.foo2(): 2
derived.foo3(): 3
unrelated.foo3(): 3
9.3. private, public, and protected inheritance
class A{
public:
int x;
protected:
int y;
private:
int z;
};
class B : public A {
// x is public
// y is protected
// z is not accessible from B
};
class C : protected A {
// x is protected
// y is protected
// z is not accessible from C
};
// 'private' is default for classes
class D : private A {
// x is private
// y is private
// z is not accessible from D
};
9.4. ตัวอย่างการเปลี่ยนการเข้าถึงด้วยการสืบทอด
ฟังก์ชัน getArea() ไม่สามารถเข้าถึงจาก main() เพราะการเข้าถึงถูกเปลี่ยนเป็น protectec ด้วยการสืบทอด
class Rect{
public:
int width,height;
Rect(){}
int getArea(){ return width*height; }
protected:
int key;
};
class Square: protected Rect{
public:
Square(int edge){
width=edge;
height=edge;
cout<<key<<endl; //ok
cout<<width<<endl; //ok
}
};
int main(){
Square mysq(5);
//cout<<"mysq.area() is "<<mysq.getArea()<<endl; //cannot access getArea()
return 0;
}
9.4.1 private inheritance with scope (avoid using this confused pattern)
ถ้าไม่ใช้ scope "A::", B จะไม่สามารถเข้าถึง print() เพราะสืบทอดแบบ private เราไม่ควรใช้ pattern นี้ในการเขียนโปรแกรมเพราะอาจเกิดความสับสนเรื่องการเข้าถึง
#include<iostream>
using namespace std;
class A{
public:
void print(){cout<<"it's A"<<endl;}
};
class B:private A{
public:
void print(){
cout<<"it's B"<<endl;
A::print();
}
};
class C: private B{
public:
void print(){
cout<<"it's C"<<endl;
B::print();
}
};
int main(){
C c;
c.print();
return 0;
}
output
Running /home/ubuntu/workspace/code941_private_inheritance.cpp
it's C
it's B
it's A
9.4.2 protected inheritance
ถ้าต้องการป้องกันการเข้าถึงจากนอกคลาส protected inheritance จะเข้าใจได้ง่ายมากกว่า private inheritance
#include<iostream>
using namespace std;
class A{
public:
void print1(){cout<<"it's A"<<endl;}
};
class B:protected A{
public:
void print2(){
cout<<"it's B"<<endl;
print1();
}
};
class C: public B{
public:
void print3(){
cout<<"it's C"<<endl;
//if class B: private, C cannot access print1() (with in class C)
//if class B: protected, C can access print1() (with in
print2();
}
};
int main(){
C c;
c.print3();
return 0;
}
output
Running /home/ubuntu/workspace/code941_private_inheritance.cpp
it's C
it's B
it's A
9.5. Order of constructing and destructing
ถ้ามีการสืบถอดหลายชั้น ลำดับการสร้างและการทำลายจะเป็นอย่างไร
#include<iostream>
using namespace std;
class A{
public:
A(){
cout<<"Constructing A"<<endl;
}
~A(){
cout<<"Destructing A"<<endl;
}
};
class B:private A{
public:
B(){
cout<<"Constructing B"<<endl;
}
~B(){
cout<<"Destructing B"<<endl;
}
};
class C: private B{
public:
C(){
cout<<"Constructing C"<<endl;
}
~C(){
cout<<"Destructing C"<<endl;
}
};
int main(){
C c;
return 0;
}
output
Running /home/ubuntu/workspace/code950_sequenceConDeCon.cpp
Constructing A
Constructing B
Constructing C
Destructing C
Destructing B
Destructing A
9.5.1 order of constraction and deconstruction
สังเกตผลลัพธ์ในการสร้างและทำลาย a1 และ a2 โดยการสร้างเป็นไปตามลำดับซ้ายไปขวา ส่วนการทำลายจะเริ่มทำลายตัวที่ถูกสร้างหลังสุดก่อน
#include<iostream>
using namespace std;
class A{
public:
int id;
A(int _id=0){
id=_id;
cout<<"Constructing A "<<id<<endl;
}
~A(){cout<<"Destructing A "<<id<<endl;}
};
class B:public A{
public:
A a1,a2;
B():a1(1),a2(2){cout<<"Constructing B"<<endl;}
~B(){cout<<"Destructing B"<<endl;}
};
class C:public B{
public:
C(){cout<<"Constructing C"<<endl;}
~C(){cout<<"Destructing C"<<endl;}
};
int main(){
C c;
return 0;
}
output
Running /home/ubuntu/workspace/code950_sequenceConDeCon.cpp
Constructing A 0
Constructing A 1
Constructing A 2
Constructing B
Constructing C
Destructing C
Destructing B
Destructing A 2
Destructing A 1
Destructing A 0