C++ 개발자 면접에서 반복적으로 등장하는 핵심 질문들을 정리했습니다. C와 C++의 차이, 포인터와 참조의 차이, 가상 함수(virtual function), 그리고 this 포인터까지, 실전 면접에서 꼭 알아야 할 개념들을 예제 코드와 함께 살펴보겠습니다.
1. C와 C++의 차이점은 무엇인가요?
C와 C++은 문법적으로 유사하지만, 언어의 설계 철학과 지원하는 프로그래밍 패러다임에서 큰 차이가 있습니다. 아래 표에서 주요 차이점을 확인해 보세요.
| 구분 | C | C++ |
|---|---|---|
| 개발 배경 | 데니스 리치(Dennis Ritchie)가 1969년경 AT&T 벨 연구소에서 개발 | 비야네 스트롭스트룹(Bjarne Stroustrup)이 1979년에 개발 |
| 언어 유형 | 절차적 프로그래밍(Procedural Programming) 언어 | 절차적 프로그래밍과 객체지향 프로그래밍(OOP)을 모두 지원 |
| OOP 기능 지원 | OOP 개념을 지원하지 않아 다형성, 캡슐화, 상속을 사용할 수 없음 | 객체지향 언어로서 다형성, 캡슐화, 상속을 모두 지원 |
| 데이터 보안 | 캡슐화를 지원하지 않아 데이터가 외부 코드에 의해 자유롭게 조작될 수 있음 | 캡슐화를 통해 데이터를 숨기고, 데이터 구조와 연산자가 의도된 대로만 사용되도록 보장 |
| 구동 방식 | 함수 중심(Function-driven) 언어로 알려짐 | 객체 중심(Object-driven) 언어로 알려짐 |
| 지원 기능 | 함수 오버로딩과 연산자 오버로딩을 지원하지 않으며, 네임스페이스와 참조 변수 기능도 없음 | 함수 및 연산자 오버로딩을 지원하고, 네임스페이스와 참조 변수 기능 제공 |
2. 포인터와 참조의 차이점은 무엇인가요?
포인터(pointer)와 참조(reference)는 모두 다른 변수를 간접적으로 다루는 방법이지만, 다음과 같은 중요한 차이가 있습니다.
역할: 참조는 기존 변수를 다른 이름으로 부르는 별칭(alias) 역할을 하고, 포인터는 변수의 메모리 주소를 저장합니다.
null 값: 참조에는 null 값을 할당할 수 없지만, 포인터에는 null을 할당할 수 있습니다.
전달 방식: 참조 변수는 값 전달(pass by value)처럼 사용되며, 포인터는 참조 전달(pass by reference) 방식으로 활용됩니다.
초기화: 참조는 선언 시 반드시 초기화해야 하지만, 포인터는 선언 후 나중에 초기화해도 됩니다.
메모리 구조: 참조는 원본 변수와 동일한 메모리 주소를 공유하며 스택에 약간의 공간을 차지하고, 포인터는 스택에 자신만의 독립적인 메모리 주소와 크기를 가집니다.
3. C++의 가상 함수(Virtual Function)란?
가상 함수는 기반 클래스(base class) 포인터 목록을 만들고, 파생 클래스(derived class) 객체의 실제 타입을 몰라도 해당 클래스의 메서드를 호출할 수 있게 해주는 기능입니다. 가상 함수는 컴파일 시점이 아닌 런타임에 늦게 바인딩(late binding)되어 해석됩니다.
기반 클래스의 멤버 함수를 virtual 키워드로 한 번 선언하면, 해당 기반 클래스로부터 파생된 모든 클래스에서 이 함수는 자동으로 가상 함수가 됩니다. 따라서 파생 클래스에서 재정의할 때는 virtual 키워드를 생략해도 됩니다.
예제
#include<iostream>
using namespace std;
class B {
public:
virtual void s() {
cout<<" In Base \n";
}
};
class D: public B {
public:
void s() {
cout<<"In Derived \n";
}
};
int main(void) {
D d; // D 클래스의 객체
B *b= &d; // d를 가리키는 B* 타입의 포인터
b->s(); // "D::s() called" 출력
return 0;
}실행 결과
In Derived
포인터 b는 기반 클래스 타입이지만, 가상 함수 덕분에 실제 객체인 파생 클래스 D의 함수가 호출됩니다. 이것이 바로 다형성(polymorphism)의 핵심 원리입니다.
4. C++의 this 포인터란?
C++의 모든 객체는 this 포인터라고 불리는 특별한 포인터를 통해 자기 자신의 주소에 접근할 수 있습니다. this 포인터는 모든 멤버 함수에 암묵적으로 전달되는 매개변수이며, 멤버 함수 내부에서 호출한 객체 자신을 가리키는 데 사용됩니다.
단, 프렌드(friend) 함수는 클래스의 멤버가 아니므로 this 포인터를 가지지 않습니다. this 포인터는 오직 멤버 함수에만 존재합니다.
다음 예제를 통해 this 포인터의 개념을 확인해 보겠습니다.
예제
#include <iostream>
using namespace std;
class Box {
public:
// 생성자 정의
Box(double l = 2.0, double b = 2.0, double h = 2.0) {
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
}
double Volume() {
return length * breadth * height;
}
int compare(Box box) {
return this->Volume() > box.Volume();
}
private:
double length; // 상자의 길이
double breadth; // 상자의 너비
double height; // 상자의 높이
};
int main(void) {
Box Box1(3.3, 1.2, 1.5); // Box1 선언
Box Box2(8.5, 6.0, 2.0); // Box2 선언
if(Box1.compare(Box2)) {
cout << "Box2 is smaller than Box1" <<endl;
} else {
cout << "Box2 is equal to or larger than Box1" <<endl;
}
return 0;
}실행 결과
Constructor called. Constructor called. Box2 is equal to or larger than Box1
compare() 함수 내부에서 this->Volume()은 호출한 객체(Box1)의 부피를 계산하고, 매개변수로 전달된 box.Volume()은 비교 대상(Box2)의 부피를 계산합니다. 이처럼 this 포인터를 사용하면 같은 클래스의 두 객체를 손쉽게 비교할 수 있습니다.
마무리
C와 C++의 차이, 포인터와 참조, 가상 함수, this 포인터는 C++ 면접에서 가장 기본이 되면서도 자주 출제되는 질문입니다. 각 개념의 동작 원리를 예제 코드와 함께 직접 실행해 보면서 확실히 익혀두면 면접에서 자신 있게 답변할 수 있을 것입니다.