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 : 가상함수
> 무엇을 하는지 정의되어 있지 않는 함수
> 오버라이딩 되어야만 함
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 로 가져와서 중복 방지
+
다중상속,, 나중에