TIL

[241230 TIL] C++ 공부_객체 선언, 포인터와 참조 등

yoosorang 2024. 12. 30. 21:33
❗ New Knowledge

using namespace std;는 std::를 생략하기 위해서 선언한 것

min_element(arr.begin(), arr.end());

std::string substr(size_t pos = 0, size_t count = std::string::npos) const;
pos: 추출을 시작할 위치 (기본값: 0).
count: 추출할 문자의 개수. 기본값은std::string::npos로, 문자열의 끝까지 추출함.

▪이동시멘틱 : operator 연산자의 하위 개념 -> 면접에서도 가장 어려운 개념(언리얼 내에서는 알아서 처리함)

▪ 생성/소멸 시기를 잘 판단해서 선언 및 생성을 어디에서 해야함

new 키워드로 힙 메모리에 객체 생성한 경우 해당 객체를 가리키는 포인터를 사용해야만 접근 가능

▪  vector의 push_back임시 객체를 만들어서 거기에 값을 복사 후 vecotor 에 삽입함

▪  포인터는 nullptr 값을 가질 수 있고 참조는 반드시 유효한 객체를 참조해야 함(nullptr 가질 수 없음)

1️⃣ C++ 개념 강의

🔹 TO-DO LIST 구현하기

private: 
	string name;
	int age;

public:
	Student(string studentName, int studentAge) : name(studentName), age(studentAge){}

	string getName() const {
		return name;
	}

	int getAge() const {
		return age;
	}

	string getInfo() {
		return "학생 이름: " + name + "\n학생 나이: " + to_string(age);
	}
};

class StudentPrinter {
public:
	void print(Student& student) {
		cout << student.getInfo();
	}
};

int main() {
	unique_ptr<StudentPrinter> printer = make_unique<StudentPrinter>(); 
	//프린터는 하나만 있어도 되니까 -> 이 unique 스마트 포인터 이 개념에 사용되는 게 아닌가봄
	//StudentPrinter printer = StudentPrinter(); //객체 정적 생성
    	//StudentPrinter printer; 로만 써도 되는디
    
    
	//StudentPrinter* printer = new StudentPrinter(); //객체 동적 생성 및 포인터 할당
	//unique_ptr<StudentPrinter> printer = make_unique<StudentPrinter>(); //위에 업그레이드 버전

	//->여기서는 main에서 객체가 생성되어 여기서만 사용되니까 굳이

	Student student1 = Student("John Doe", 20);
	//학생 객체 생성
	//여러 학생을 생성하고 싶을 땐 vector 주로 사용

	printer->print(student1);
	printer.print(student1);
	
	return 1;
}
💭자아성찰
클래스 객체이름; 만 써도 객체 생성 되는데 난 여지껏 뭘 쓰고 있었던 거지...
객체가 언제, 어디에서 사용되는지도 잘 파악해야함

🔹TO-DO LIST 구현하기

#include <iostream>
#include <vector>
#include <string>

using namespace std;

class Task {
private:
    string description;
    bool completed = false;
public:
    Task(string desc) : description(desc) {};

    void complete() {
        if (!completed)
            completed = true;
    }

    string getDescription() const {
        return description;
    }

    bool isCompleted() const {
        return completed;
    }
};

class IStorage {
public:
    virtual void addTask(Task task) = 0;

    virtual vector<Task> getTasks() = 0;

    virtual string getStorageType() = 0;
};

class TaskManager {
    IStorage* storage;

public:
    TaskManager(IStorage* s) : storage(s) {} 
    //레퍼런스가 아닌 포인터로 받은 이유가 있나? -> 포인터로 받으면 nullptr을 가질 수 있음
    //레퍼런스는 항상 유효한 객체를 요구함
    //만약 IStorage가 항상 유효하고 TaskManager가 객체의 생명 주기를 관리하지 않는다면 레퍼런스 사용이 괜찮

    // 새로운 할 일 추가
    void addTask(const string& description) {

        storage->addTask(Task(description));
    }

    // 현재 할 일 목록 출력
    void showTasks() {
        cout << "저장 방식: " << storage->getStorageType() << "\n";
        vector<Task> tasks = storage->getTasks(); //함수 내에서만 사용되니까 함수에서 생성
        for (size_t i = 0; i < tasks.size(); ++i) {
            cout << i + 1 << ". " << tasks[i].getDescription();
            if (tasks[i].isCompleted()) cout << " [완료]";
            cout << "\n";
        }
    }

    // 특정 할 일을 완료 처리
    void completeTask(size_t index) {
        vector<Task> tasks = storage->getTasks(); 
        if (index > 0 && index <= tasks.size()) {
            tasks[index - 1].complete();
            storage->addTask(tasks[index - 1]); // 변경된 할 일 저장
        }
        else {
            cout << "잘못된 번호입니다.\n";
        }
    }
};

class MemoryStorage : public IStorage{
    vector<Task> tasks;

    void addTask(Task task) {
        tasks.push_back(task);
    }

    vector<Task> getTasks() {
        return tasks;
    }

    string getStorageType() {
        return "메모리 저장소";
    }

};

class DBStorage : public IStorage {
    vector<Task> tasks;

    void addTask(Task task) {
        //만약 여기에서 
        tasks.push_back(task);
        cout << "DB에 할 일 추가: " << task.getDescription() << endl;
    }

    vector<Task> getTasks() {
        return tasks;
        cout << "DB에서 할 일 가져오기" << endl;
    }

    string getStorageType() {
        return "DB 저장소 (시뮬레이션)";
    }

};




// 메인 함수
int main() {
    cout << "=== MemoryStorage로 작업 ===\n";
    MemoryStorage memoryStorage;
    TaskManager manager1(&memoryStorage);

    manager1.addTask("C++ 과제 작성하기");
    manager1.addTask("SOLID 원칙 공부하기");

    cout << "\n현재 할 일 목록:\n";
    manager1.showTasks();

    manager1.completeTask(1);

    cout << "\n업데이트된 할 일 목록:\n";
    manager1.showTasks();

    cout << "\n=== DBStorage로 작업 ===\n";
    DBStorage dbStorage;
    TaskManager manager2(&dbStorage);

    manager2.addTask("DB 작업 테스트");
    manager2.addTask("To-Do 목록 추가");

    cout << "\n현재 할 일 목록:\n";
    manager2.showTasks();

    manager2.completeTask(2);

    cout << "\n업데이트된 할 일 목록:\n";
    manager2.showTasks();

    return 0;
}
💭자아성찰
const & 사용하기!