본문 바로가기

Language/C++

[C++] 상속(Inheritance) - 컴도리돌이

728x90

Outline

Inheritance

Overriding

Constructor, Destructor & Inheritance

Multiple Inheritance

const & Class


상속(Inheritance)

  • 부모 클래스(parent class)를 자식 클래스(child class)에 상속을 시키면 부모 클래스(parent class)의 private 값을 제외한 함수, 변수는 자식 클래스(child class)에서 사용이 가능하다. 상속받을 클래스의 이름 옆에 :와 접근 제한자, 그리고 상속할 클래스의 이름을 붙여주면 된다.

상속 : Is-a 관계( Inheritance : Is-a Relationship)

  • "A가 B이다.(A is a B)"라는 관계가 형성될 때 상속을 사용할 수 있다.

  • 예를 들면 "자동차는 탈 수 있다.", "트럭은 탈 수 있다." 관계는 성립되지만 "탈 수 있는 것은 자동차이다."라는 표현은 어색하게 된다.

언어에 따라서 부르는 방식이 다르다.

class Vehicle {
public:
   Vehicle() {}
   void Accelerate();
   void Decelerate();
   LatLng GetLocation();
   double GetSpeed();
   double GetWeight();
private:
   LatLng location_;
   double speed_;
   double weight_;
};

class Car : public Vehicle {
public:
   Car() : Vehicle() {}
   int GetCapacity();
private:
   int capacity_;
};

class Truck : public Vehicle {
public:
   Truck() : Vehicle() {}
   double GetMaxLoad();
private:
   double max_load_;
};

오버 라이딩(Overriding)

  • 오버 라이딩(Overriding)은 상속받은 클래스의 member function을 재정의하여 사용한다.

  • *오버 로딩(overloading)과 헷갈리지 말자!! (함수의 이름을 동일하게 사용할 수 있게 허용하는 것!!)*
class Car : public Vehicle {
public:
   Car() : Vehicle() {}
   
   int GetCapacity();
   // Override the parent's GetWeight().
   
   double GetWeight() {
  	 return Vehicle::GetWeight() + passenger_weight_;
 }
private:
   int capacity_;
   double passenger_weight_;
};
  • 상속받은 GetWeight() 함수를 상속을 받지 않았지만 해당 Car 클래스 자체에서 상속받은 함수를 재정의 할 수 있다. 위에 예시를 보면 추가적으로 상속받은 함수를 재정의를 하였다.

  • 주의 : 부모 클래스에 상속을 받았어도 private의 값은 절대 상속되지 않는다!!(물론 할 수 있는 방법은 있다.)


생성자, 소멸자 & 상속(Constructor, Destructor & Inheritance)

  • 상속받은 클래스가 메인(main)에서 생성(Constructor)될 때, 상위 상속 클래스로부터 생성(Constructor)된다. 반대로 메인에서 괄호로 인해 정의된 클래스가 종료될 때는 하위 상속받은 클래스부터 상위 상속 클래스까지 소멸(Destructor)된다.

 

class Parent {
public:
   Parent() { cout << " Parent"; }
   ~Parent() { cout << " ~Parent"; }
};

class Child : public Parent {
public:
   Child() { cout << " Child"; }
   ~Child() { cout << " ~Child"; }
};

class Test : public Child {
public:
   Test() { cout << " Test"; }
   ~Test() { cout << " ~Test"; }
};

int main() {
   {
     Child child;
     cout << endl;
   }
   cout << endl;
   {
     Test test;
     cout << endl;
   }
   cout << endl;
   return 0;
}
Parent Child
 ~Child ~Parent
 Parent Child Test
 ~Test ~Child ~Parent
  • 예시를 보면 첫 중괄호에서 Child 클래스의 child가 정의될 때, Child를 상속해주는 Parent 클래스부터 생성된다. 반대로 중괄호가 끝날 때는 Child클래스부터 상속 클래스가 삭제된다.

다중 상속(multiple inheritance)

  • 상속하는 클래스가 2개 이상일 때 다중 상속(Multiple Inheritance)라고 한다. 

  • 다수의 클래스로부터 상속받을 경우, 이름이 같은 member variable, function을 상속받았을 경우에 문제가 생깄을 수 있다.(Ambiguity)

 

 


const & Class

Const member variables

  • 멤버 변수를 const로 지정하여 변경시킬 수 없게 설정을 한다. 
class Circle {
private:
 	double radius;
 	const double PI;
public:
 Circle(double r, double p) : radius(r), PI(p) {}
 ...
  • 위에 예시에서 Circle을 생성할 때(Constructor) private값(radius, PI)을 인자로 받는데, PI는 const로 설정되어 있다. PI의 값을 설정하기 위해서 : PI(p)처럼 괄호를 사용하여 설정을 해줘야 한다.

Const member functions

  • 멤버 함수도 const로 지정하면 멤버 변수를 읽을 수는 있지만 멤버 변수를 업데이트를 할 수 없다.
class Circle {
private:
   double radius;
   const double PI;
public:
 Circle(double r, double p) : radius(r), PI(p) {}
 void SetRadius(double r) { radius = r; }
 double GetArea() const { return PI * radius * radius;}
};
  • 위에 예시를 보면 GetArea() 함수를 const로 지정했다. 함수 내부를 보면 단순히 멤버 변수를 읽어서 반환(return)해주기 때문에 문제가 발생하지 않는다.

  • 함수 내부에서 멤버 변수를 변경하거나, 일반적인 함수가 있을 경우 에러가 발생한다.

  • const로 지정한 함수만 읽는다.(일반적인 함수가 어떠한 업데이트가 없어도 컴파일러는 모르기 때문에 함수가 const로 지정되어 있지 않으면 컴파일 에러 신호를 보낸다.)

Const object

int main() {
   Circle cir(2.0);
   cout << cir.GetArea() << endl;
   cir.SetRadius(3.0);
   cout << cir.GetArea() << endl;
   
   const Circle cir2(3.0);
   cout << cir.GetArea() << endl;
   cir.SetRadius(4.0); // Error
   cout << cir2.GetArea() << endl;
   
   return 0;
}
  • const로 지정한 class는 멤버 변수를 업데이트할 수 없다.

  • const로 지정하지 않은 멤버 함수(non-const member functions)를 호출할 수 없다.