1. 클래스와 상속


inheritance를 사용한 클래스 구현의 예시코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
 
#define NAME_SIZE 50
 
using namespace std;
 
class Person{
    int id;
    char name[NAME_SIZE];
    
public:
    void aboutMe(){
        cout<<"I am a person.";
    }        
};
 
class Student : public Person{
public:
    void aboutMe(){
        cout<<"I am a student.";
    }        
};
 
int main(void){
    Student *= new Student();
    p->aboutMe();    //"I am a student." 출력 
    delete p;    //할당 받은 메모리를 반환하는것이 중요! 
    return 0;    
}
cs


실행결과


1. C++에서 모든 멤버 데이터와 메소드(함수)는 기본적으로 private이다.


2. public 키워드로 그 값을 변경할 수 있다.


3. 생성자 p는 포인터 이므로 ->로 멤버 메소드를 호출할 수 있다.



2. 생성자와 소멸자


1. 생성자(constructor)는 객체가 생성되면 자동으로 호출된다.


2. 생성자가 정의되어있지 않으면 기본생성자(default constructor)라고 불리는 생성자를 자동 생성한다.


3. 객체 생성시 초기화를 하고싶다면 다음 두가지 방법과 같이 할 수 있다.

 Person(int a){

     id = a;

 } 

 Person(int a) : id(a){

     ...

 }


4. 멤버변수 id는 실제 객체가 생성되기전, 그리고 생성자 코드의 나머지 부분이 실행되기 전에 값을 할당받는다. 이 방식은 상수 혹은 클래스형 필드를 초기화할때 유용하다.


5. 소멸자(destructor) 역시 객체가 소멸될 때 자동으로 호출되며, 할당받은 메모리를 반환하여 메모리 관리에 유리하다.


6. 소멸자는 명시적으로 호출할 수 있는 메소드가 아니므로 전달인자없이 기본소멸자(default)밖에 없다.



3. 가상 함수


1. 정적 바인딩(static binding)


위의 코드에서 아래와 같이 p는 Student* 타입으로 정의를 했는데, 

 Student *p = new Student();

 p->aboutMe(); 

다음과 같이 p를 Person* 타입으로 정의하면 어떻게 될까?

 Person *p = new Student();

 p->aboutMe(); 

실행결과


aboutMe() 메소드가 어떤 타입인지는 컴파일 시간에 결정되기 때문에 "I am a person." 이 출력된다.

이런 메커니즘을 정적 바인딩(static binding)이라고 한다.


2. 가상 함수(virtual function)


만약 Student 클래스에서 구현된 aboutMe() 메소드를 호출하고 싶다면 아래와 같이 Person 클래스의 aboutMe() 메소드를 virtual로 선언해야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public:
    virtual void aboutMe(){
        cout<<"I am a person.";
    }        
};
 
class Student : public Person{
public:
    void aboutMe(){
        cout<<"I am a student.";
    }        
};
 
int main(void){
    Person *= new Student();
    p->aboutMe();    //"I am a student." 출력 
    delete p;    //할당 받은 메모리를 반환하는것이 중요! 
    return 0;    
}
cs


부모클래스에 어떤 메서드를 구현해 둘 수 없는(혹은, 구현하고 싶지 않은) 경우에도 가상함수(virtual function)를 사용한다.

예를들어, 부모클래스 Person으로부터 자식클래스 Student와 Teacher 두개의 클래스가 상속받는다고 하자.

Student와 Teacher클래스 모두 addCourse() 라는 메소드를 가지고 있을때, Student 클래스냐 Teacher 클래스냐에 따라 addCourse() 메소드 구현 자체가 달라지므로, 부모클래스인 Person 클래스에서 addCourse() 메소드를 구현하면 안된다.

따라서 이때, Person클래스의 addCourse는 순수 가상 함수(pure virtual function)로 선언하여 그 구현은 하위 클래스에게 맡겨야한다.

이해를 돕기위한 아래 코드를 첨부한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
 
#define NAME_SIZE 50
 
using namespace std;
 
class Person{
    int id;
    char name[NAME_SIZE];
    
public:
    virtual void aboutMe(){
        cout<<"I am a person."<<'\n';
    }        
    virtual bool addCourse(string s) = 0;
};
 
class Student : public Person{
public:
    void aboutMe(){
        cout<<"I am a student."<<'\n';
    }
    
    bool addCourse(string s){
        cout<<"Added course "<< s <<" to student." <<'\n';
        return true;
    }
};
 
int main(void){
    Person *= new Student();
    p->aboutMe();    //"I am a student." 출력 
    p->addCourse("C++ programming");
    delete p;    //할당 받은 메모리를 반환하는것이 중요! 
    return 0;    
}
cs


실행결과


addCourse() 메소드를 순수 가상 함수로 선언하였으므로 Person 클래스는 스스로 객체를 만들어 낼 수 없는 추상 클래스(abstract class)가 된다.



4. 가상 소멸자


Person과 Student 클래스의 소멸자를 구현하면 다음과 같이 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
 
using namespace std;
 
class Person{
public:
    virtual ~Person(){
        cout<< "Deleting a person." <<endl;
    }
};
 
class Student : public Person{
public:
    ~Student(){
        cout<< "Deleting a student." <<endl;
    }
};
 
int main(){
    Person *= new Student();
    delete p;
}
cs


main() 함수에서 p의 타입은 Person이므로, ~Person() 메소드를 virtual로 선언하지 않으면 Student에 배정된 메모리가 제대로 반환되지 않을 수 있다.

따라서 ~Person() 메소드를 virtual로 선언해 줘야 한다.


실행결과




면접 지식 기반 문제

C/C++(1) 

'Interview' 카테고리의 다른 글

면접 지식 기반 문제_C/C++(2)  (0) 2019.01.30
Posted by Jyoel :