#include <iostream>
#define MAX 10
using namespace std;
typedef struct Node
{
int data;
struct Node* Next;
} Node;
Node* Insert(Node* node, int data) // 데이터 추가
{
if (node == NULL)
{
Node* newNode = new Node();
newNode->data = data;
newNode->Next = NULL;
return newNode;
}
node->Next = Insert(node->Next, data);
return node;
}
Node* Search(Node* node, int data) // 데이터 탐색
{
if (node == NULL)
{
return NULL;
}
if (node->data == data)
{
return node;
}
return Search(node->Next, data);
}
Node* Delete(Node* node, int data) // 데이터 삭제
{
if (node == NULL)
{
return NULL;
}
if (node->data == data)
{
Node* nextNode = node->Next;
free(node);
return nextNode;
}
node->Next = Delete(node->Next, data);
return node;
}
void Print(Node* node)
{
if (node == NULL)
{
return;
}
cout << node->data;
Print(node->Next);
}
int main()
{
Node* head = NULL;
// 데이터 추가
for (int i = 0; i < MAX; i++)
{
head = Insert(head, i);
}
cout << "결과 : ";
Print(head);
cout << '\n';
// 데이터 탐색
cout << "결과 : ";
Node* someNode = Search(head, 5);
if (someNode != NULL)
{
cout << someNode->data << '\n';
}
// 데이터 삭제
cout << "결과 : ";
head = Delete(head, 4);
Print(head);
return 0;
}
class monster
{
public:
monster(const string name);
void SetHealthPoint(int HealtPoint);
private:
string mName;
int mHealthPoint;
int mMaxHealthPoint;
};
[예제]
class Hz
{
private string host; // field
public string Host // property
{
get { return host; } // get 메서드
set { host = value; } // set 메서드
}
}
클래스 안 필드는, 읽기전용/쓰기전용으로 설정 가능.
※ 읽기 전용 : get 메소드만 사용.
※ 쓰기 전용 : set 메소드만 사용.
유연성↑. (즉, 다른 부분에 영향 안 주고, 코드 일부만 변경 가능.)
데이터 보안 강화.
#include <iostream>
#define MAX 101
using namespace std;
void ReverseString(char* str)
{
int n = strlen(str);
for (int i = 0; i < n / 2; i++)
{
int tmp = str[i];
str[i] = str[n - i - 1];
str[n - i - 1] = tmp;
}
cout << str;
}
int main()
{
char c[MAX];
cin >> c;
ReverseString(c);
return 0;
}
int number1 = 3;
long number2 = number1; // 암시적 캐스팅
static_cast
const_cast
dynamic_cast (C++98, 모던 C++)
reinterpret_cast
정적 캐스트는 값에 쓰일 수도, 개체에 쓰일 수도 있다. 값에 쓰일 경우 두 숫자 형 간의 변환이며 값을 유지한다. (반올림 오차는 제외) 하지만 이진수 표기는 달라질 수도 있다.
float num1 = 3.f;
int num2 = static_cast<int>(num1);
C++에서 가장 위험한 캐스팅 중 하나이다. 이 캐스팅이 위험한 이유는 다음과 같다.
전혀 연관이 없는 두 포인터 형 사이의 변환을 허용한다. (ex. Cat <-> House, char <-> int)
포인터와 포인터 아닌 변수 사이의 형 변환을 허용한다. (ex. Cat* <-> unsigned int)
정적 캐스팅과 다른 점은, 리인터프리터 캐스트는 이진수 표기가 달라지지 않는다는 점이다.
int* signedNumber = new int(-10);
unsigned int* unsignedNumber = reinterpret_cast<unsigned int*>(signedNumber);
const_cast는 형을 바꿀 수는 없다. 오직 const나 volatile 어트리뷰트를 제거할 때 사용한다.
Animal* myPet = new Cat(2, "Owen");
const Animal* petPtr = myPet;
Animal* myAnimal1 = (Animal*)petPtr; // OK
Cat* myCat1 = (Cat*)petPtr; // OK
Animal* myAnimal2 = const_cast<Animal*>(petPtr); // OK
Cat* myCat2 = const_cast<Cat*>(petPtr); // Compile Error, static_cast를 사용해야 함
const_cast는 포인터 형에서만 사용이 가능하다. 값 형은 언제나 복사가 되기 때문이다. 그리고 const_cast를 코드에서 쓰려고 한다면 이는 문제가 있는 것이다. 이 캐스팅을 쓸 때는 서드파티 라이브러리에서 const를 제대로 사용하지 않았을 때와 같은 경우만 사용하는 것이 바람직하다.
동적 캐스트는 실행 중에 형을 판단한다. 그리고 포인터나 참조 형을 캐스팅 할 때만 쓸 수 있다. 또한 호환되지 않는 자식형으로 캐스팅을 하려 하면 NULL을 반환한다. 따라서 dynamic_cast가 static_cast보다 안전하다.
하지만 이 캐스팅을 쓰려면 컴파일 중에 RTTI(실시간 타입정보, Real-Time Type Information)를 켜야 한다. 참고로 이 옵션은 C++ 프로젝트에서는 성능적인 이슈로 끄는 경우가 일반적이다. RTTI가 꺼져 있으면 dynamic_cast와 static_cast가 동일하게 동작한다.
// 동적 캐스팅(dynamic casting)
Cat* myCat = dynamic_cast<Cat*>(myPet);
이때 만들어지는 함수는 모두 기본형(default)이다. 그리고 모두 public이며 inline함수이다.
class Empty {
public:
Empty() { ... } // 기본생성자
Empty(Empty& rhs) { ... } // 복사생성자
~Empty() { ... } // 소멸자
Empty& operator=(const Empty& rhs) { ... } // 복사 대입 연산자
};
컴파일러가 생성하는 함수는 모두 public 멤버가 된다. 복사 생성자와 복사 대입 연산자가 저절로 만들어지는 것을 막기 위해 private 멤버로 선언하면, 일단 클래스 멤버 함수가 명시적으로 선언되기 때문에, 컴파일러는 자신의 기본 버전을 만들 수 없고, 이 함수들이 비공개(private)의 접근성을 가지므로, 외부로부터의 호출을 차단할 수 있다.
그러나 private 멤버 함수는 그 클래스의 멤버 함수 및 프렌드(friend) 함수가 호출할 수 있다는 문제점이 남아있다. 이것을 막으려면 정의(define)를 안 해 버리면 된다. 정의되지 않은 함수를 누군가가 호출하려 했다면 링크 시점에 에러를 보게 된다.