따라하며 배우는 C++
10. 객체 사이의 관계들에 대해
10.1 객체들의 관계
구성(요소) : Composition, Part-of -- 관계와 객체가 분리될 수 없음.
집합 : Aggregation, Has-a -- 연결이 느슨함. 관계와 객체가 분리될 수 있음.
연계, 제휴: Association, Uses-a -- 단순히 사용하는 관계
의존 : Dependency, Depends-on
10.2 구성 관계 Composition
Monter.h
#pragma once
#include "Position2D.h"
#include <string>
class Monster
{
private:
std::string m_name; //string = char * data, unsigned int length
//location
Position2D m_location;
public:
Monster(const std::string name_in, const Position2D & pos_in)
:m_name(name_in), m_location(pos_in)
{
}
void moveTo(const Position2D& pos_target)
{
m_location.set(pos_target);
}
friend std::ostream & operator << (std::ostream& out, Monster& monster)
{
out << monster.m_name << " " << monster.m_location;
return out;
}
};
Position2D.h
#pragma once
#include <iostream>
class Position2D
{
private:
int m_x;
int m_y;
public:
Position2D(const int& x_in, const int& y_in)
:m_x(x_in), m_y(y_in)
{}
//TODO: ovaerload operator =
void set(const Position2D & pos_target)
{
set(pos_target.m_x, pos_target.m_y);
}
void set(const int& x_target, const int& y_target)
{
m_x = x_target;
m_y = y_target;
}
friend std::ostream& operator << (std::ostream& out, const Position2D& pos2d)
{
out << pos2d.m_x << " " << pos2d.m_y;
return out;
}
};
Source.cpp
#include <iostream>
#include "Monster.h"
using namespace std;
int main()
{
Monster mon1("Sanson", Position2D(0, 0));
cout << mon1 << endl;
{
mon1.moveTo(Position2D(1, 1));
cout << mon1 << endl;
}
return 0;
}
이처럼 Monster가 Position을 사용하는 관계를 Composition이라고 한다.
Position이 Monster의 멤버이지만 나중에 다른 클래스에서 재활용할 수도 있는 관계.
10.3 집합 관계 Aggregation
#include <iostream>
#include <vector>
#include <string>
#include "Lecture.h"
using namespace std;
int main()
{
using namespace std;
//Composition Relationship
Lecture lec1("Introduction to Computer Programming");
lec1.assignTeacher(Teacher("Prof. Hong"));
lec1.registerStudent(Student("Jack Jack", 0));
lec1.registerStudent(Student("Dash", 1));
lec1.registerStudent(Student("Violet", 2));
Lecture lec2("Computational Thinking");
lec1.assignTeacher(Teacher("Prof. Good"));
lec1.registerStudent(Student("Jack Jack", 0));
lec1.registerStudent(Student("Dash", 1));
lec1.registerStudent(Student("Violet", 2));
//TODO : implement Aggregation Relationship
//tset
{
cout << lec1 << endl;
cout << lec2 << endl;
//event
lec2.study();
cout << lec1 << endl;
cout << lec2 << endl;
}
return 0;
}
Composition으로 일반적으로 구현하면 동일 학생이라도 Lecture에 따라 다른 개체로 인식된다.
Lecture.h
#pragma once
#include <vector>
#include "Student.h"
#include "Teacher.h"
class Lecture
{
private:
std::string m_name;
//Composition : 객체와 멤버 변수가 운명을 같이 한다.
Teacher teacher;
std::vector<Student> students;
//Teacher* teacher;
//std::vector<Student*> students;
public:
Lecture(const std::string& name_in)
:m_name(name_in)
{}
~Lecture()
{
//do Not delete teacher
//do Not delete students
}
void assignTeacher(const Teacher & const teacher_input)
{
teacher = teacher_input;
}
/*
void assignTeacher(Teacher * const teacher_input)
{
teacher = teacher_input;
}
*/
void registerStudent(const Student& const student_input)
{
students.push_back(student_input);
}
/*
void registerStudent(Student * const student_input)
{
students.push_back(student_input);
}
*/
void study()
{
std::cout << m_name << " Study " << std::endl << std::endl;
for (auto& element : students) //Note : 'auto element' doesn't work
element.setIntel(element.getIntel() + 1);
/*
for(auto element : students)
(*element).setIntel((*element).getIntel() + 1);
*/
}
friend std::ostream& operator << (std::ostream& out, const Lecture& lecture)
{
out << "Lecture name : " << lecture.m_name << std::endl;
out << lecture.teacher << std::endl;
for (auto element : lecture.students)
out << element << std::endl;
/*
out << *lecture.teacher << std::endl;
for(auto element : lecture.students)
out << *element << std::endl;
*/
return out;
}
};
Student.h
#pragma once
#include <iostream>
#include <string>
class Student
{
private:
std::string m_name;
int m_intel;
//TODO: add more members like address, phone, favorite food ...
public:
Student(const std::string & name_in = "No Name", const int & intel_in = 0)
: m_name(name_in), m_intel(intel_in)
{}
void setName(const std::string& name_in)
{
m_name = name_in;
}
void setIntel(const int& intel_in)
{
m_intel = intel_in;
}
int getIntel()
{
return m_intel;
}
const std::string& getName()
{
return m_name;
}
friend std::ostream& operator << (std::ostream& out, const Student& student)
{
out << student.m_name << " " << student.m_intel;
return out;
}
};
Teacher.h
#pragma once
#include <string>
class Teacher
{
private:
std::string m_name;
//TODO: more members like home address, salary, age, evaluation, etc;.
public:
Teacher(const std::string& name_in = "No Name")
: m_name(name_in)
{}
void setName(const std::string& name_in)
{
m_name = name_in;
}
std::string getName()
{
return m_name;
}
friend std::ostream& operator << (std::ostream& out, const Teacher& teacher)
{
out << teacher.m_name;
return out;
}
};
위와 같이 만들면, 같은 학생일지라도 제대로 인식이 되지 않는다.
source.cpp
#include <iostream>
#include <vector>
#include <string>
#include "Lecture.h"
using namespace std;
int main()
{
using namespace std;
Student std1("Jack Jack", 0);
Student std2("Dash", 1);
Student std3("Violet", 2);
Teacher teacher1("Prof. Hong");
Teacher teacher2("Prof. Good");
//Composition Relationship
Lecture lec1("Introduction to Computer Programming");
lec1.assignTeacher(&teacher1);
lec1.registerStudent(&std1);
lec1.registerStudent(&std2);
lec1.registerStudent(&std3);
Lecture lec2("Computational Thinking");
lec2.assignTeacher(&teacher2);
lec2.registerStudent(&std1);
//TODO : implement Aggregation Relationship
//tset
{
cout << lec1 << endl;
cout << lec2 << endl;
//event
lec2.study();
cout << lec1 << endl;
cout << lec2 << endl;
}
return 0;
}
Lecture.h
#pragma once
#include <vector>
#include "Student.h"
#include "Teacher.h"
class Lecture
{
private:
std::string m_name;
//Composition : 객체와 멤버 변수가 운명을 같이 한다.
/*Teacher teacher;
std::vector<Student> students;*/
Teacher* teacher;
std::vector<Student*> students;
public:
Lecture(const std::string& name_in)
:m_name(name_in)
{}
~Lecture()
{
//do Not delete teacher
//do Not delete students
}
/*
void assignTeacher(const Teacher & const teacher_input)
{
teacher = teacher_input;
}
*/
void assignTeacher(Teacher * const teacher_input)
{
teacher = teacher_input;
}
/*
void registerStudent(const Student& const student_input)
{
students.push_back(student_input);
}
*/
void registerStudent(Student * const student_input)
{
students.push_back(student_input);
}
void study()
{
std::cout << m_name << " Study " << std::endl << std::endl;
/*
for (auto& element : students) //Note : 'auto element' doesn't work
element.setIntel(element.getIntel() + 1);
*/
for(auto element : students)
(*element).setIntel((*element).getIntel() + 1);
}
friend std::ostream& operator << (std::ostream& out, const Lecture& lecture)
{
out << "Lecture name : " << lecture.m_name << std::endl;
/*
out << lecture.teacher << std::endl;
for (auto element : lecture.students)
out << element << std::endl;
*/
out << *lecture.teacher << std::endl;
for(auto element : lecture.students)
out << *element << std::endl;
return out;
}
};
Student.h
#pragma once
#include <vector>
#include "Student.h"
#include "Teacher.h"
class Lecture
{
private:
std::string m_name;
//Composition : 객체와 멤버 변수가 운명을 같이 한다.
/*Teacher teacher;
std::vector<Student> students;*/
Teacher* teacher;
std::vector<Student*> students;
public:
Lecture(const std::string& name_in)
:m_name(name_in)
{}
~Lecture()
{
//do Not delete teacher
//do Not delete students
}
/*
void assignTeacher(const Teacher & const teacher_input)
{
teacher = teacher_input;
}
*/
void assignTeacher(Teacher * const teacher_input)
{
teacher = teacher_input;
}
/*
void registerStudent(const Student& const student_input)
{
students.push_back(student_input);
}
*/
void registerStudent(Student * const student_input)
{
students.push_back(student_input);
}
void study()
{
std::cout << m_name << " Study " << std::endl << std::endl;
/*
for (auto& element : students) //Note : 'auto element' doesn't work
element.setIntel(element.getIntel() + 1);
*/
for(auto element : students)
(*element).setIntel((*element).getIntel() + 1);
}
friend std::ostream& operator << (std::ostream& out, const Lecture& lecture)
{
out << "Lecture name : " << lecture.m_name << std::endl;
/*
out << lecture.teacher << std::endl;
for (auto element : lecture.students)
out << element << std::endl;
*/
out << *lecture.teacher << std::endl;
for(auto element : lecture.students)
out << *element << std::endl;
return out;
}
};
Teacher.h
#pragma once
#include <vector>
#include "Student.h"
#include "Teacher.h"
class Lecture
{
private:
std::string m_name;
//Composition : 객체와 멤버 변수가 운명을 같이 한다.
/*Teacher teacher;
std::vector<Student> students;*/
Teacher* teacher;
std::vector<Student*> students;
public:
Lecture(const std::string& name_in)
:m_name(name_in)
{}
~Lecture()
{
//do Not delete teacher
//do Not delete students
}
/*
void assignTeacher(const Teacher & const teacher_input)
{
teacher = teacher_input;
}
*/
void assignTeacher(Teacher * const teacher_input)
{
teacher = teacher_input;
}
/*
void registerStudent(const Student& const student_input)
{
students.push_back(student_input);
}
*/
void registerStudent(Student * const student_input)
{
students.push_back(student_input);
}
void study()
{
std::cout << m_name << " Study " << std::endl << std::endl;
/*
for (auto& element : students) //Note : 'auto element' doesn't work
element.setIntel(element.getIntel() + 1);
*/
for(auto element : students)
(*element).setIntel((*element).getIntel() + 1);
}
friend std::ostream& operator << (std::ostream& out, const Lecture& lecture)
{
out << "Lecture name : " << lecture.m_name << std::endl;
/*
out << lecture.teacher << std::endl;
for (auto element : lecture.students)
out << element << std::endl;
*/
out << *lecture.teacher << std::endl;
for(auto element : lecture.students)
out << *element << std::endl;
return out;
}
};
source.cpp에서 선언된 인스턴스를 다른 곳에서도 써야 할 때는 Student *std1 = new Student(~~) 처럼 동적으로 구현하기도 한다. 대신에 꼭 delete는 해 주어야 한다.
위의 경우는 lecture 두 개의 객체가 한 개의 student들을 공유하고 있는 형태이다.
그러나 분산 처리에선 아예 다른 컴퓨터들이 작동하기 때문에 "사본"을 가질 수 밖에 없다.
그러므로 정보 업데이트를 위한 싱크로나이즈, 동기화 작업이 필요하다.
10.4 제휴 관계 Association
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Doctor; //forward declaration
//전방 선언일 경우 Association관계일 가능성이 높다.
class Patient
{
private:
string m_name;
vector<Doctor*> m_doctors;
public:
Patient(string name_in)
: m_name(name_in)
{ }
void addDoctor(Doctor* new_doctor)
{
m_doctors.push_back(new_doctor);
}
void meetDoctors();
friend class Doctor;
};
class Doctor
{
private:
string m_name;
vector<Patient*> m_patients;
public:
Doctor(string name_in)
: m_name(name_in)
{ }
void addPatient(Patient* new_patient)
{
m_patients.push_back(new_patient);
}
friend class Patient; //멤버 직접 접속 가능.
void meetPatients()
{
for (auto& ele : m_patients)
{
cout << "Meet patients : " << ele->m_name << endl;
}
}
};
void Patient::meetDoctors()
{
for (auto& ele : m_doctors)
{
cout << "Meet doctor : " << ele->m_name << endl;
}
}
int main()
{
Patient* p1 = new Patient("Jack Jack");
Patient* p2 = new Patient("Dash");
Patient* p3 = new Patient("Violet");
Doctor* d1 = new Doctor("Doctor K");
Doctor* d2 = new Doctor("Doctor L");
p1->addDoctor(d1);
d1->addPatient(p1);
p2->addDoctor(d2);
d2->addPatient(p2);
p2->addDoctor(d1);
d1->addPatient(p2);
//patients meet doctors
p1->meetDoctors();
//doctors meet patients
d1->meetPatients();
//deletes
delete p1;
delete p2;
delete p3;
delete d1;
delete d2;
return 0;
}
Reflecsive 제휴관계 : class 안에 같은 class를 참조하는 것!
10.5 의존 관계 Dependency
source.cpp
#include "Worker.h"
using namespace std;
int main()
{
Worker().doSomething();
return 0;
}
Worker.h
#include "Worker.h"
using namespace std;
int main()
{
Worker().doSomething();
return 0;
}
Worker.cpp
#include "Worker.h"
#include "Timer.h"
#pragma once
void Worker::doSomething()
{
Timer timer;
//do some work here
timer.elapsed();
}
Timer.h
#pragma once
#include <vector>
#include <string>
#include <chrono>
#include <iostream>
#include <random>
#include <algorithm>
using namespace std;
class Timer
{
using clock_t = chrono::high_resolution_clock;
using second_t = chrono::duration<double, ratio<1>>;
chrono::time_point<clock_t> start_time = clock_t::now();
public:
void elapsed()
{
chrono::time_point<clock_t> end_time = clock_t::now();
cout << chrono::duration_cast<second_t>(end_time - start_time).count() << endl;
}
};
10.6 컨테이너 클래스
vector나 array가 container.
Standard Template Library > Containers
ㅇㅇ가 ㅇㅇ의 멤버다라는 관계를 표시하기 좋다.
#include <iostream>
using namespace std;
/* Assignment */
class IntArray
{
private:
int m_length = 0;
int* m_data = nullptr;
public:
//Constructors
//Destructors
//initialize()
//reset();
//resize();
//insertBefore(const int & value, const int & ix);
//remove(const int &ix);
//push_back(const int &value);
};
int main()
{
//IntArray my_arr{1, 3, 5, 7, 9 };
//my_arr.insertBefore(10, 1); //1, 10, 3, 5, 7, 9
//my_arr.remove(3); //1, 10, 3, 7, 9
//my_arr.push_back(13); //1, 10, 3, 7, 9, 13
return 0;
}
'개발 공부 > C++' 카테고리의 다른 글
따라하며 배우는 C++ 12. 가상 함수들 (0) | 2020.07.02 |
---|---|
따라하며 배우는 C++ 11. 상속 (0) | 2020.07.02 |
따라하며 배우는 C++ 9. 연산자 오버로딩 (0) | 2020.07.02 |
따라하며 배우는 C++ 8. 객체지향의 기초 (0) | 2020.07.01 |
따라하며 배우는 C++ 7. 함수 (0) | 2020.07.01 |