C++/모두의코드

6장

twoweeks-within 2025. 2. 2. 20:07
Employee **employee_list; 

 

단일 포인터 vs 이중포인터 

   : 값을 넣느냐, 주소를 넣느냐..

Employee **list = (Employee **)malloc(n * sizeof(Employee *));
// 이걸로 일단 공간을 만들고
list[0] = (Employee *)malloc(sizeof(Employee));
list[1] = (Employee *)malloc(sizeof(Employee));
// 이렇게 값을 개별적 malloc 공간으로 넣을 수 있음

// 나중에 추가하고 싶으면
n = 4;
list = (Employee **)realloc(list, n * sizeof(Employee *));
// 공간을 다시 만들어주고
    list[2] = (Employee *)malloc(sizeof(Employee));
    list[3] = (Employee *)malloc(sizeof(Employee));
    list[2]->id = 1002;
    list[3]->id = 1003;
// 내용물 추가해도 기존의 것은 유지됨

 

>> 개별적으로 malloc 할 수 있다는건,.,

     개별적으로 추가, 삭제, 수정 뿐아니라

     개별적으로 다른 sizeof를 넣을 수 있다!

list[0] = (Employee *)malloc(sizeof(Employee));   // 기본 크기
list[1] = (Employee *)malloc(sizeof(Employee));   // 기본 크기
list[2] = (Employee *)malloc(2 * sizeof(Employee)); // 🔥 2개 크기 할당!
list[3] = (Employee *)malloc(3 * sizeof(Employee)); // 🔥 3개 크기 할당!

<>

이중포인터는 유동적으로 관리가능

단일포인터는 똑같은 크기로 주루룩 붙음

 

대신 해제할때도 개별적으로 해제해야함 > 한번에 지울땐 for문 사용

 

상속 (Inheritance)

   : 다른 클래스의 정보를 물려 받음

// friend 는 그 클래스의 일부 변수를 사용

class Derived : public Base

Derived 는 base 를 물려받는다 , public 형식으로

 

----------------------------------------------------------------------------

  Base() : s("기반") {  std::cout << "기반 클래스" <<  std::endl; }

// Base 클래스 내부

   Base() : s("기반") { std::cout << "기반 클래스" << std::end1; }

      : Base() 를 생성하면서 // defualt

         + s 에 "기반" 을 넣어줌

------------------------------------------------------------------------------

Derived() : Base(), s("파생") {
   std::cout << "파생 클래스" <<  std::endl;

  // Base 에서 what() 을 물려 받았으므로
  // Derived 에서 당연히 호출 가능하다
  what();
}

 > Derived c; // 호출

 

1. 기반의 Base() 를 먼저 들림 // Base(),s("기반") 을 먼저

2. Derived(),s("파생") // 이때 s 는 파생의 s에 적용됨

 

3. 이때의 what 은 기반 함수것이라서 기존의 " 기반 " 이 출력

>

 void what() {  std::cout << s <<  std::endl; }

 파생 클래스 public 내부에도 what 생성

    > 같은이름, 같은 인자를 받았지만 다른 함수임 !

>> Overriding : 굳이 멀리 Base 까지 가지 않고 가까운 Derived 에서 호출함

 

protected  : 상속받는 클래스에서만 접근 가능 , 그외는 X

// private는 상속받아도 접근 불가능 하므로

 protected:
  std::string parent_string;

>>

 

class Derived : public Base

여기서 

Public      : 기반의 pulic, protected, private 을 그냥 그대로 받음 

protected : 기반의 pulic > protected  , 나머지는 그대로

private      : 모든게 다 private가 됨

 

>>>

class Derived : private Base {
  std::string child_string;
  Base p;
  std::cout << p.parent_string << std::endl;
// Base 에서는 public 이므로 가능

  Derived c;
  std::cout << c.parent_string << std::endl;
// Derived 에서는 private 로 받아왔기에 접근 불가

>> 추가설명

 

class Base {
public:
    void baseFunction() { cout << "Base 기능" << endl; }
};

class Derived : private Base {  // ✅ private 상속
public:
    void derivedFunction() {
        cout << "Derived 기능" << endl;
        baseFunction();  // ✅ 상속받은 클래스 내부에서만 Base 기능 사용 가능
    }
};

int main() {
    Derived d;
    // d.baseFunction();  // ❌ 오류! Base의 public 멤버가 private으로 변경됨
    d.derivedFunction(); // ✅ 가능! 이건 그냥 지거 public 이라

  > 프로그래머의 잘못된 사용을 막고, 부모클래스의 기능을 내부적으로만 사용

     > 외부에서는 사용 못받게함 

>>>> 객체지향 OOP  : object-oriented programming

            : 독립적이지만, 때론 연결되고, 상속,포인터 등으로 협력하고

              > main에서조차 독립된

         : 클래스를 통해 생성한 객체들 끼리도 독립적임 

            ex) Car car1; Car car2;  // 각각 독립적인 값, 주소를 가짐

        // 클래스 : 설계도, 제조메뉴얼 <> 객체 : 그걸 

 

#6.2

 

업 캐스팅

Base* p_c = &c;

// p_c : Base 형태

// c     : Derived 형태

 

       > p : Base 포인터라서 Derived 형태인 c 에서 Base 부분만 가져옴

         > 파생 클래스에서 기반 클래스로 캐스팅 하는것 

            :: 업캐스팅

<>

다운캐스팅

 Derived* p_p = &p;
  p_p->what();

 // Base p;

베이스를 가져왔는데 Derived 에서 what을 찾으려고 하면 없음

 

virtual 키워드

 

class Base(){ virtual what() }

Base* p_c = &c; // Derived c;

p_c->what();

  

> 컴파일러가 Derived 에서 c를 가져온걸 알고 Dervied 에 있는 what()을 실행함

>> " 동적 바인딩"

 

override 키워드

  : 파생에서 기반의 virtual (함수)를 우선하는 경우

     > 명시적으로 알려줌

 

 다형성(polymorphism) 

 

//

 

class Employee{

    virtual int calculate_pay() { return 200 + rank * 50; }
};
class Manager : public Employee{

     int calculate_pay() override { return 200 + rank * 50 + 5 * year_of_service; }
 };

 

void add_employee(Employee* employee) {

    employee_list[current_employee] = employee;   
}

 

emp_list.add_employee(new Manager("유재석", 41, "부장", 7, 12));

 

>>

Manager를 넣었지만 employee 에게 상속 받았음 > override 업캐스팅해서 > Manager에서 있는 calculate_pay 함수 사용

 

 

virtual 소멸자

Base의 즉, 기반의 소멸자들을 virtual 로 해주면

소멸을 빼먹는 실수로 인한 메모리 누수 발생 x

 

 

??? : virtual이 사기네..

class Parent {
 public:
  virtual void func1();
  virtual void func2();
};
class Child : public Parent {
 public:
  virtual void func1();
  void func3();
};

virtual function table;

활용성은 좋음 다만 시간이 쪼금 더 걸림..

 

virtual function : 가상함수

   > 무엇을 하는지 정의되어 있지 않는 함수 

      > 오버라이딩 되어야만 함

class Animal {

  virtual void speak() = 0;

 

// 순수가상함수 : pure

}

>

가상함수가 하나라도 포함되어있는 클래스는

Animal a;

와 같이 객체 생성못함..

   >> 추상(abstract) 클래스

 

> 사용하는 이유

   Animal 이 speak 하는건 맞지만 동물마다 소리가 다 다름

    > Animal 클래스를 받아와서 너에게 맞는 소리를 구현해!

+

Animal* cat = new Cat();
cat->speak();

그래도 포인터 ( Animal *) 형태로는 가능

 

다중상속

class C : public A, public B {
 public:
  int c;
};

 

A도 받아오고 B도 받아옴

순서 : 먼저 받아온순 : A -> B-> C

 > public B, public A 라면 

     : B ->A -> C

 

다중상속시 주의..

 class A 에도 a , class B 에도 a 가 있다면

    > C  c;

      c.a =3; 라고 컴파일 할시 오류 발생

 

다이아몬드 상속

 

 

Human 에 name 변수가 있다면..

> Handsome 과 smart 에 name 이 있으니

> 중복해서 가져옴

class Human {
 public:
  // ...
};
class HandsomeHuman : public virtual Human {
  // ...
};
class SmartHuman : public virtual Human {
  // ...
};
class Me : public HandsomeHuman, public SmartHuman {
  // ...
};

 > virtual 로 가져와서 중복 방지

 

+

다중상속,, 나중에

'C++ > 모두의코드' 카테고리의 다른 글

7장  (0) 2025.02.04
5장 // 5.3 뒷부분은 복습때  (0) 2025.02.01
4장 이어서..  (0) 2025.01.31
3장, 4장  (0) 2025.01.30
1장  (0) 2025.01.29