[ 클래스와 상속 ]
C++에서 모든 데이터 멤버와 메서드는 기본적으로 private입니다. public 키워드를 사용하면 그 값을 변경할 수 있습니다. Person이라는 class를 제작하고 Person을 상속하는 Student라는 class를 만들면 다음과 같습니다.
#include
using namespace std;
# define NAME_SIZE 50 // 매크로 정의
class Person{
int id;
char name[NAME_SIZE];
public:
void aboutMe(){
count << "I am a person.";
}
};
class Student : public Person{
public:
void aboutMe(){
count << "I am a student.";
}
};
int main(){
Studnet * p = new Student();
p->aboutMe(); // "I am a student" 출력
delete p; // 할당 받은 메모리 반환
return 0;
}
[ 생성자와 소멸자 ]
👀생성자
객체가 생성되면 자동으로 호출됩니다. 사용자가 생성자를 만들거나 생성자가 정의되어 있지 않으면 컴파일러는 기본 생성자라고 불리는 생성자를 자동으로 만듭니다.
Person(int a){
id = a;
}
// 기본형 변수 초기화
Person(int a) : id(a){
...
}
위의 id(데이터 멤버)는 실제 객체가 만들어지기 전, 그리고 생성자 코드의 나머지 부분이 실행되기 전에 값을 할당받습니다. 이런 방식은 상수 혹은 클래스형 필드를 초기화할 때 유용합니다.
👀 소멸자
객체가 소멸될 때 자동으로 호출됩니다. 객체를 삭제하는 작업으로 인자를 전달할 수 없습니다.
~Person(){
delete obj; // 클래스 안에서 할당한 메모리 반환
}
[ 가상 함수 ]
Student * p = new Student();
p->aboutMe(); // "I am a student" 출력
Person * p = new Student();
p->aboutMe(); // "I am a person" 출력
파생 클래스에서 재정의할 것으로 기대하는 멤버 함수를 의미합니다. 위의 예제들은 가상 함수가 아니기 때문에 모두 정적 바인딩을 하게 되므로 [Person * p = new Student(); p->aboutMe();]에서 Student 클래스에서 구현된 aboutMe를 호출하지 않습니다. Student 클래스에서 구현된 aboutMe를 호출하고 싶다면, Person class의 aboutMe 메서드를 가상함수(virtual)로 선언해야 합니다.
⭐ 가상 함수의 경우 결합하는 타입이 분명할 때에는 일반 함수와 같이 정적 바인딩을 하나 기초 클래스 타입의 포인터나 참조를 통하여 호출될 때만 동적 바인딩을 하게 됩니다.
class Person{
...
virtual void aboutMe(){
count << "I am a person.";
}
};
class Student : public Person{
public:
void aboutMe(){
count << "I am a student.";
}
};
이 외에 부모 클래스에 어떤 메서드를 구현해 둘 수 없는(혹은, 구현하고 싶지 않은) 경우에도 가상 함수를 사용합니다.
[ 가상 소멸자 ]
동적으로 할당된 메모리를 정상적으로 제거하기 위해서 가상 소멸자를 선언해야 합니다.
class Person{
public:
virtual ~Person(){
count << "Deleting a person." << endl;
}
};
class Student : public Person{
public:
~Student(){
count << "Deleting a student." << endl;
}
};
int main(){
Person * p = new Student();
delete p; // 출력 : Deleting a student.\nDeleting a person.
}
[ 기본값 ]
함수를 제작할 때 기본값은 반드시 함수 선언의 우측 부분에 설정해야 합니다.
int func(int a, int b=3){
x = a;
y = b;
return a + b;
}
w = func(4);
z = func(4, 5);
[ 연산자 오버로딩 ]
연산자 오버로딩 기능을 사용하면 +와 같은 연산자를 객체 간 연산에도 사용할 수 있습니다. 가령 두 개의 BookShelf 객체를 하나로 합치고 싶을 때, +연산자를 다음과 같이 오버로딩하면 됩니다.
BookShelf BookShelf::operator+(BookShelf &other){ ... }
[ 포인터와 참조 ]
👀 포인터
포인터는 변수의 주소를 담는 변수입니다. 변수의 값을 읽거나 변경하는 등, 변수에 적용 가능한 연산은 모두 포인터를 통해 할 수 있습니다.
⭐ 포인터 변수의 크기는 아키텍처에 따라 달라집니다. 32비트 컴퓨터면 32비트, 64비트 컴퓨터면 64비트입니다.
int * p = new int;
*p = 7;
int * q = p;
*p = 8;
count << *q; // 8 출력
👀 참조
참조는 기존에 존재하는 객체에 붙는 또 다른 이름이며, 별도의 메모리를 갖지 않습니다.
⭐ 참조는 포인터와 달리 null이 될 수 없으며 다른 메모리에 재할당 될 수도 없습니다.
int a = 5;
int & b = a;
b = 7;
count << a; // 7 출력
[ 템플릿 ]
하나의 클래스를 서로 다른 여러 타입에 재사용할 수 있도록 하는 방법입니다.
template <typename T>
T add(T x, T y){
return x + y;
}
a = add(1, 2);
b = add(0.5, 0.3);
'프로그램 개발 > 미분류' 카테고리의 다른 글
[코딩 인터뷰]지식 기반 문제 - Java (0) | 2023.01.11 |
---|---|
[코딩 인터뷰]지식 기반 문제 - C와 C++ 문제 (0) | 2023.01.06 |
[코딩 인터뷰]개념과 알고리즘 - 정렬과 탐색 (1) | 2023.01.03 |
[코딩 인터뷰]개념과 알고리즘 - 시스템 설계 및 규모 확장성 (0) | 2023.01.02 |
[코딩 인터뷰]개념과 알고리즘 - 재귀와 동적 프로그래밍 (0) | 2022.12.26 |