TIL::Today I Learn

[TIL] 20230707

madylin 2023. 7. 8. 16:46
반응형

오늘 공부한 내용📓

- C++

개념 공부

Orthodox Canonical Form

  • OCCF 란, 클래스의 기본적인 형식 또는 일반적인 형식을 따르는 규칙 집합
  • 이 규칙들은 클래스의 일관성과 호환성을 유지하고, 예기치 않은 동작을 방지하는데 도움을 줌
  • C++ 98 버전의 OCCF 는 아래 규칙을 포함함
    • 기본 생성자(Default Constructor)
    • 복사 생성자(Copy Constructor)
    • 소멸자(Destructor)
    • 대입 연산자(Assignment Operator)
    • 동등 연산자(Equality Operator)
    • 복사 할당 연산자(Copy Assignment Operator)
    • ostream 연산자(’<<’) 오버로딩
    • istream 연산자(’>>’) 오버로딩
  • 42 과제에서는 위 규칙들 중 기본 생성자, 복사 생성자, 복사 할당 연산자, 소멸자만을 필수로 요구함

오버로딩(Overloading)

  • 같은 이름을 가진 함수나 연산자가 다양한 매개변수로 다른 동작을 수행할 수 있도록 하는 기능
  • 동일한 이름의 함수나 연산자를 여러번 정의할 수 있고, 함수나 연산자 호출 시에 전달되는 인자의 유형이나 개수에 따라 적절한 함수나 연산자가 선택됨
  • 오버로딩은 함수 오버로딩과 연산자 오버로딩으로 나뉨
    • 함수 오버로딩
      • 동일한 이름을 가진 함수가 서로 다른 매개변수 목록을 가지도록 허용하는 기능
      • 함수의 이름을 재사용하며, 비슷한 동작을 하는 여러 함수를 구현하는데 유용함
    • int add(int a, int b) { return a + b; } int add(double a, double b) { return a + b; } int main() { add(1,2); //int add(int a, int b) 함수가 호출됨 add(1.1, 2.2); //int add(double a, double b) 함수가 호출됨 return 0; }
    • 연산자 오버로딩
      • C++에서 기본적으로 제공되는 연산자(+,-,* 등)에 대해 사용자가 동작을 정의할 수 있게 하는 기능
      • 클래스나 구조체에 대해 기존 연산자를 재정의하여 원하는 동작을 수행할 수 있음
    • class Vector { private: double x, y; public: Vector(double x, double y) : x(x), y(y) {} Vector operator+(const Vector& other) const { return Vector(x + other.x, y + other.y); } }

복사 생성자(Copy Constructor)

  • 다른 객체의 값을 복사하여 새로운 객체를 생성하며, 일반적으로 참조로 전달
  • 복사생성자는 기본적으로 c++ 컴파일러에서 제공되며, 사용자가 별도로 정의하지 않아도 자동으로 생성됨. 디폴트 복사 생성자는 얕은 복사를 함.
  • MyClass obj1; //MyClass 의 객체 obj1을 생성 MyClass obj2(obj1); //obj1을 사용하여 obj2를 복사 생성자 호출
  • 복사 생성자는 기존 값을 복사해 전달하는 개념이기 때문에, 값이 변경되지 않도록 const 로 선언한다.
  • class MyClass { publick: MyClass(const MyClass& other){ //객체 복사 } }
  • 얕은 복사(Shallow Copy)란?
    • 단순히 원본 객체의 주소를 복사 대상 객체에 할당하는 것
    • 원본 객체와 복사된 객체는 동일한 메모리를 공유함
  • class MyClass { public: int* data; MyClass(const MyClass& other) { // 주소만 복사되고 데이터는 공유됨 data = other.data; } };
  • 깊은 복사(Deep Copy)란?
    • 복사 대상 객체에 새로 메모리를 할당하여 데이터를 복사하는 것
    • 원본 객체와 복사된 객체가 다른 메모리를 갖기 때문에, 변경이 발생해도 서로 영향을 주지 않음
    • 복사 생성자나 대입 연산자 오버로딩을 통해 수행될 수 있음
  • class MyClass { public: int* data; MyClass(const MyClass& other) { // 새로운 메모리를 할당하고 데이터를 복사함 data = new int(*other.data); } ~MyClass() { delete data; // 메모리 해제 } };

대입 연산자(Assignment Operator)

class MyClass {
public:
    // 대입 연산자 오버로딩
    MyClass& operator=(const MyClass& other) {
        // 대입 연산자의 본문에는 객체를 복사하는 로직이 들어감
        // 다른 멤버 변수들을 다른 객체에서 복사하여 할당하는 등의 작업을 수행할 수 있음
        if (this != &other) { // 자기 자신에게 대입하는지 확인
            // 멤버 변수 복사
        }
        return *this; // 대입 후 자기 자신을 반환
    }
};
  • 클래스의 객체에 다른 객체의 값을 할당하는 연산자(’=’)
  • 클래스의 멤버 변수를 다른 객체의 멤버 변수로 복사하여, 객체 간의 데이터를 교환하거나 복사할 때 주로 사용됨
  • 복사 개념이기 때문에 얕은 복사와 깊은 복사의 개념이 적용됨

동등 연산자(Equality Operator)

  • 두 개의 값을 비교하고, 동일한 값이면 true를, 다른 값이면 false 를 반환하는 연산자(’==’)
  • 기본 데이터 유형(정수, 실수 등) 뿐만 아니라 사용자가 정의한 클래스나 구조체에 대해서도 사용할 수 있음. 이 경우에는 동등 연산자 오버로딩을 통해 사용자가 직접 판단하는 방식을 정의해야 함
class Person
{
private:
	std::string name;
	int age;

public:
	Person(const std::string& name, int age) : name(name), age(age) {}

	bool operator==(const Person& other) const
	{
		return (name == other.name && age == other.age);
	}
}

복사 할당 연산자(Copy Assignment Operator)

class MyString
{
private:
	char *buffer;

public:
	MyString(const char *str)
	{
		int len = 0;
		while (str[len] != '\\0')
			len++;
		buffer = new char[len + 1];
		
		for (int i = 0; i < len; i++)
			buffer[i] = str[i];
		buffer[len] = '\\0';
	}

	MyString& operator=(const MyStyle& other) //복사 할당 연산자
	{
		if (this == &other) // 자기 자신인지 확인
			return *this;

		delete[] buffer; // 기존 할당된 메모리 해제

		int len = 0;
		while (str[len] != '\\0')
			len++;
		buffer = new char[len + 1]; // 새 메모리 할당
		
		for (int i = 0; i < len; i++)
			buffer[i] = other.buffer[i]; // 값 복사
		buffer[len] = '\\0';

		return *this;
	}
}

  • 이미 생성된 객체에 대해 다른 객체의 값을 할당하거나, 이미 할당된 메모리 자원을 해제하고 다른 값으로 다시 할당할 때 사용하는 연산자(’=’)
  • 일반적으로 반환 형식은 ‘클래스명&’ 이며, 매개변수는 ‘const 클래스명&’
  • 복사 생성자와의 차이점은 호출되는 시점과 사용되는 상황에 차이가 있음.
    • 복사 생성자 : 객체가 생성될 때, 복사 생성자를 호출하는 경우. 새로운 객체에 대해 기존 객체의 값으로 초기화 하기 위해 사용
    • 복사 할당 연산자 : 객체가 이미 생성된 후. 다른 객체의 값으로 할당하여 복사 하기 위해 사용

ostream 연산자(’<<’) 오버로딩

class Person
{
private:
	std::string name;
	int age;

public:
	Person(const std::string& name, int age) : name(name), age(age) {}

	std::ostream& print(std::ostream& os) const
	{
		os << name << age;
		return os;
	}
}

// ostream 연산자 오버로딩
std::ostream& poerator<<(std::ostream& os, const Person& person)
{
	return person.print(os);
}
  • ‘<<’ 연산자는 std::ostream 객체에 대한 출력을 수행하는 연산자로, ‘<<’ 연산자를 오버로딩하여 사용자가 정의한 클래스나 구조체에 대한 출력 동작을 지정할 수 있음
  • 반환 형식은 출력 스트림 객체를 참조 형식(std::ostream&)으로 반환하고, 매개변수를 출력 스트림 객체(std::ostream&)와 출력하고자 하는 사용자 정의 클래스(또는 구조체) 객체를 받음

istream 연산자(’>>’) 오버로딩

class Person
{
private:
	std::string name;
	int age;

public:
	Person() {}

	std::istream& read(std::istream& is)
	{
		is >> name >> age;
		return is;
	}
}

std::istream& operator>>(std::istream& is, Person& person)
{
	return person.read(is);
}
  • ‘>>’ 연산자는 std::istream 객체에서 입력을 수행하는 연산자로, ‘>>’ 연산자를 오버로딩하여 사용자가 정의한 클래스나 구조체에 대한 입력 동작을 지정할 수 있음
  • 반환 형식은 입력 스트림 객체를 참조 형식(std::istream&)으로 반환하고, 매개변수를 입력 스트림 객체(std::istream&)와 입력받고자 하는 사용자 정의 클래스(또는 구조체) 객체를 받음

 

 

제가 공부한 내용을 기록하고 있습니다.

혹시 수정이 필요한 부분이 있다면, 댓글로 지적 부탁드립니다!

선한 관심과 도움 감사드립니다😊

반응형

'TIL::Today I Learn' 카테고리의 다른 글

[TIL] 2023714  (1) 2023.07.18
[TIL] 20230708  (0) 2023.07.18
[TIL] 20230705  (0) 2023.07.06
[TIL] 20230704  (0) 2023.07.06
[TIL] 20230622  (0) 2023.06.24