1. 클래스의 선언과 정의
클래스의 선언
class MyClass {
public:
// 멤버 변수 (속성)
int myVariable;
// 멤버 함수 (메서드)
void myFunction();
};
다음은 클래스 선언에 대한 예시입니다.
클래스에는 멤버 변수와, 멤버 함수를 선언할 수 있습니다.
클래스의 정의
void MyClass::myFunction() {
// 멤버 함수의 구현
// myVariable을 사용할 수 있음
// 다른 작업 수행
}
다음은 클래스 정의에 대한 예시입니다.
멤버 함수의 구현부에 대해서 정의를 수행할 수 있습니다.
2. 클래스의 접근 지정자
클래스의 접근 지정자에는 public, private, protected로 세가지 종류가 있습니다.
public
class MyClass {
public:
// 공개 멤버 변수
int publicVariable;
// 공개 멤버 함수
void publicFunction() {
// 구현
}
};
// 클래스 인스턴스 생성
MyClass obj;
// 외부에서 공개 멤버에 직접 접근 가능
obj.publicVariable = 42;
obj.publicFunction();
public은 클래스 외부에서 사용할 수 있는 접근 지정자 형태입니다.
클래스의 인터페이스를 형성하고, 외부 코드가 해당 기능을 사용할 수 있게 합니다.
private
class MyClass {
private:
// 비공개 멤버 변수
int privateVariable;
// 비공개 멤버 함수
void privateFunction() {
// 구현
}
};
// 클래스 인스턴스
MyClass obj;
// 외부에서 비공개 멤버에 직접 접근 불가능
// 아래 주석을 해제하면 컴파일 오류 발생
// obj.privateVariable = 42;
// obj.privateFunction();
private 멤버는 클래스 내부에서만 접근이 가능하며, 외부에서는 직접 접근할 수 없습니다. 클래스의 내부 구현을 숨기고, 데이터 은닉과 보안을 제공합니다
protected
class MyBaseClass {
protected:
// 보호 멤버 변수
int protectedVariable;
// 보호 멤버 함수
void protectedFunction() {
// 구현
}
};
class MyDerivedClass : public MyBaseClass {
public:
void AccessProtectedMember() {
// 파생 클래스에서 보호 멤버에 접근 가능
protectedVariable = 10;
protectedFunction();
}
};
// 클래스 인스턴스 생성
MyDerivedClass derivedObj;
// 외부에서는 보호 멤버에 직접 접근 불가능
// 아래 주석을 해제하면 컴파일 오류 발생
// derivedObj.protectedVariable = 42;
// derivedObj.protectedFunction();
// public 함수를 통한 간접 접근
derivedObj.AccessProtectedMember()
protected 멤버는 기본적으로 클래스 내부에서는 접근이 가능하고, 파생 클래스에서도 접근이 가능합니다. 이는 상속 관계에서 파생 클래스가 기본 클래스의 일부 멤버에 접근할 수 있도록 하는 데 사용됩니다.
3. 생성자와 소멸자
class MyClass {
public:
// 생성자
MyClass() {
// 초기화 코드
}
// 소멸자
~MyClass() {
// 객체 파괴 시 실행할 코드
}
};
-----------------------
생성자
class MyClass {
public:
// 디폴트 생성자 (매개변수 없는 생성자)
MyClass() {
// 초기화 코드
}
// 매개변수를 받는 생성자
MyClass(int x, int y) {
// 초기화 코드
}
};
생성자는 객체가 생성될 때 호출되는 함수로, 객체의 초기화를 담당합니다.
생성자 멤버 초기화 리스트
class MyClass {
private:
int x;
int y;
public:
// 생성자에서 초기화
MyClass(int a, int b) : x(a), y(b) {
// 다른 초기화 코드
}
};
생성자에서 멤버 변수를 다음과 같은 형태로 초기화 할수도 있습니다.
생성자의 호출 시점
- 객체 선언 시: 객체가 선언되면 해당 클래스의 생성자가 호출됩니다.
Copy code
MyClass obj; // 생성자 호출
- 동적 할당 시 : new 연산자를 사용하여 객체를 동적으로 할당할 때 생성자가 호출됩니다.
MyClass *ptr = new MyClass; // 생성자 호출
- 임시 객체 생성 시: 임시 객체가 생성되면 해당 클래스의 생성자가 호출됩니다.
MyClass getTempObject() {
return MyClass(); // 생성자 호출
}
복사 생성자
C++에서 복사 생성자(Copy Constructor)는 이미 존재하는 객체를 사용하여 새로운 객체를 초기화하는 특별한 형태의 생성자입니다.
복사 생성자는 주로 객체를 전달하거나 반환할 때 발생하는 상황에서 호출되며, 한 객체의 내용을 다른 객체로 복사하는 데 사용됩니다.
class MyClass {
public:
// 복사 생성자
MyClass(const MyClass &other) {
// 복사 초기화 작업
}
};
C++ 컴파일러는 복사 생성자를 명시적으로 정의하지 않아도, 필요한 경우 자동으로 기본 복사 생성자를 생성합니다.
하지만 사용자가 직접 정의하면 컴파일러는 복사 생성자를 정의하지 않습니다.
복사 생성자 호출 시점
- 객체를 선언할 때: MyClass obj1 = obj2;와 같이 객체를 선언하면서 다른 객체로 초기화할 때 복사 생성자가 호출됩니다.
- 함수에 객체를 값으로 전달할 때: 함수의 매개변수로 객체를 값으로 전달하면 복사 생성자가 호출됩니다.
- 함수에서 객체를 값으로 반환할 때: 함수가 객체를 값으로 반환하면 복사 생성자가 호출됩니다.
복사 생성자 주의 사항
class MyClass {
public:
// ...
// 깊은 복사를 수행하는 복사 생성자
MyClass(const MyClass& other) {
// 동적으로 할당된 메모리를 새로 할당하고 데이터를 복사
data = new int(*other.data);
}
// ...
private:
int* data; // 예시로 int 형 동적 메모리를 가지는 멤버
};
복사 생성자의 동작은 객체가 가리키는 리소스가 동적으로 할당된 경우 중요해집니다.
기본적으로 C++는 얕은 복사 만을 수행합니다. 즉 포인터나 동적으로 할당된 메모리를 가진 경우 주소만 복사되어 두 객체가 같은 리소스를 공유하게 됩니다.
따라서 동적으로 할당된 리소스가 존재하는 클래스의 경우 복사 생성자를 직접 정의하여 깊은 복사 를 수행해야 할 수도 있습니다.
소멸자
class MyClass {
public:
// 생성자
MyClass() {
// 초기화 코드
}
// 소멸자
~MyClass() {
// 정리 코드
}
};
소멸자는 객체가 소멸될 때 호출되는 함수로, 객체의 정리 또는 메모리 반환과 같은 작업을 수행합니다.
클래스 이름 앞에 ~를 붙여 선언합니다.
소멸자의 호출 시점
- 객체가 블록을 빠져나갈 때: 객체가 스택에 선언되었을 때, 해당 블록을 빠져나가면서 소멸자가 호출됩니다.
{
MyClass obj; // 생성자 호출
// 블록을 빠져나가면서 소멸자 호출
}
- 동적 할당된 객체의 해제 시: delete 연산자를 사용하여 동적으로 할당된 객체를 해제할 때 소멸자가 호출됩니다.
MyClass *ptr = new MyClass; // 생성자 호출
delete ptr; // 소멸자 호출 및 메모리 해제
- 임시 객체 소멸 시: 임시 객체가 사용된 표현식이 종료될 때 소멸자가 호출됩니다.
{
MyClass obj = getTempObject(); // 임시 객체 생성, 생성자 호출
-
// 표현식이 종료되면서 소멸자 호출
}
4. this 포인터
void testFunction(int* var)
{
*var = 20;
}
int main()
{
int var = 10;
int *exInt = &var;
testFunction(exInt)
}
일반적으로 함수를 통해 객체의 값을 변경시키려면 함수에 객체의 주소값을 넘겨준 뒤 객체를 역참조 해서 객체의 주소가 가지고 있는 값을 변경시킬 수 있습니다.
class MyClass {
public:
// 멤버 변수 (속성)
int myVariable;
// 멤버 함수 (메서드)
void myFunction();
MyClass()
: myVariable(20)
{
}
};
void MyClass::myFunction()
{
myVariable = 10;
}
#include <iostream>
int main()
{
MyCLass myclass;
// 20
std::cout << myclass.myVariable << std::endl;
myclass.myFunction();
// 10
std::cout << myclass.myVariable << std::endl;
}
그런데 클래스의 멤버함수에서는 멤버 변수의 값을 변경시킬 때 클래스 객체의 주소를 전달하지 않은 것으로 보이는데도 객체의 멤버변수 값이 변경됩니다.
class MyClass {
public:
// 멤버 변수 (속성)
int myVariable;
// 멤버 함수 (메서드)
void myFunction();
MyClass()
: myVariable(20)
{
}
};
void MyClass::myFunction(
MyClass* this // 숨겨져 있음
)
{
// this->myVariable = 10;
myVariable = 10;
}
숨겨진 사실은 this 포인터라는 포인터가 그러한 역할을 대신 수행해주고 있기 때문입니다.
this 포인터는 클래스 객체가 내부의 함수를 호출 할때 자동적으로 생성되는 포인터입니다.
컴파일러는 this 포인터를 사용하지 않더라도 this 포인터를 사용한 것을 인지하고 있습니다.
?. 문제풀이
문제 1.
C++ 클래스의 접근 제어 지정자에 대한 설명을 해주세요.
문제 2.
다음 예시에서 Compile Error가 발생하는 것과 Error가 아닌 것을 구별해주세요
class A
{
A() :
num1(10),
num2(20),
num3(30)
{}
public:
int num1;
protected:
int num2;
private:
int num3;
~A(){}
}
class B : protected A
{
pulbic:
void printNum()
{
num1 = 10; // ?
num2 = 20; // ?
num3 = 45; // ?
}
}
문제 3.
복사 생성자에 대해서 설명하고 예시를 보여주세요.
'C++' 카테고리의 다른 글
C++ 자료구조 구현 이중 원형 연결 리스트 (0) | 2024.12.07 |
---|---|
C++ 자료구조 구현 Red-Black Tree (0) | 2024.11.30 |
C++ 동적할당 (0) | 2024.05.04 |
C++ 컴파일 과정 (0) | 2024.04.21 |
C++ Const 정확도(Const Correctness) (0) | 2024.04.06 |