728x90
이번 포스팅에서 우리가 배워볼 것은 다음과 같다.
- 객체 배열
- 객체 배열의 초기화
- 객체 배열 예제
- 벡터
- 벡터의 선언
- 벡터 대표 예제
- push_back()과 pop_back()
- 벡터에서 요소의 위치 : v.begin() / v.end() / v.front() / v.back()
- 벡터의 중간 부분을 삭제하기 : erase()
- 벡터와 연산자
- 벡터 예제
- array 클래스
1. 객체 배열
- 정수 배열을 생성할 수 있는 것처럼 객체들의 배열도 생성 가능하다!
- 객체 배열의 요소가 객체가 된다. 즉, 객체들이 모여 있는 컨테이너가 '객체 배열'이 되는 셈이다!
- 아래 예제를 통해서 원을 나타내는 객체를 여러개 생성하여서 화면에 그려보는 프로그램을 작성해보자.
#include <iostream> using namespace std; class Circle { public: int x, y; int radius; Circle() : x{0}, y{0}, radius{0} {} // 초기화 리스트를 이용한 기본생성자 Circle(int x, int y, int r) : x{x}, y{y}, radius{r} {} // 인수가 있는 생성자 void print() { cout << "반지름: " << radius << " @(" << x << "," << y << ")" << endl; } }; int main(void) { Circle objArray[10]; for (Circle &c : objArray) { c.x = rand() % 500; c.y = rand() % 300; c.radius = rand() % 100; } for (Circle c : objArray) c.print(); return 0; }
- 만일 객체 배열이 없었으면 아래처럼 너무 힘들게 코드를 작성했을 것이다...
Circle c1;
Circle c2;
Circle c3;
...
2. 객체 배열의 초기화
- 각 배열 요소별로 생성자를 호출하면 객체 배열 안의 객체들을 서로 다르게 초기화가 가능하다.
- 일반 배열과 같은 초기화 형태를 가지지만, 값 대신에 생성자를 호출한다.
Circle objArray[10] = {
Circle(100, 100, 30),
Circle(100, 200, 50),
Circle(100, 300, 80),
...
}
3. 객체 배열 예제
예제1 : 책들을 저장해보자
여러 권의 책을 저장할 수 있는 객체 배열 books를 생성하여 보자.
#include <iostream>
using namespace std;
class Book {
public:
string title;
int price;
Book(string name, int price) : title{name}, price{price} {}
void print() { cout << "제목: " << title << ", 가격 : " << price << endl; }
};
int main(void) {
Book objArray[2] = {Book("금도끼 은도끼", 5000), Book("C++ 교재", 10000)};
cout << "소장하고 있는 책 정보" << endl;
cout << "===================" << endl;
for (Book b : objArray)
b.print();
cout << "===================" << endl;
return 0;
};
예제 2 : 원들을 저장하자
- 10개의 원을 저장할 수 있는 배열을 선언하고 사용자가 키 'c'를 누르면 각각의 원의 위치와 반지름을 난수로 초기화한 후에 화면에 그린다. 사용자가 키 'q'를 누르면 프로그램을 종료한다.
#include <Windows.h>
#include <conio.h> //consol i/o
#include <iostream>
using namespace std;
class Circle {
public:
int x, y;
int radius;
Circle() : x{ 0 }, y{ 0 }, radius{ 0 } {}
Circle(int x, int y, int r) : x{ x }, y{ y }, radius{ r } {}
void draw() {
int r = radius / 2;
HDC hdc = GetWindowDC(GetForegroundWindow());
Ellipse(hdc, x - r, y - r, x + r, y + r);
}
};
int main(void) {
Circle objArray[10];
while (true) {
for (Circle& c : objArray) {
c.x = rand() % 500;
c.y = rand() % 300;
c.radius = rand() % 100;
c.draw();
}
char ch = _getch();
if (ch == 'q') break;
}
return 0;
}
4. 벡터
- 벡터(vector)는 동적 배열이다.
- 컴파일 시간에 배열의 크기를 미리 결정할 필요가 없다.
- 추가되는 요소의 개수에 따라서 자동적으로 크기가 조절된다.
5. 벡터의 선언
- 사용법 : 클래스 이름 뒤에 <>를 붙인 후 원하는 자료형 기입
- 클래스 템플릿으로 구현된 일종의 클래스이다.
- 클래스 인스턴스를 선언하는데 타입을 지정할 수 있다고 생각하면 쉽다
-
vector<int> scores(10); //배열의자료형 배열의이름(배열의크기); score[2] = 78; // indexing 배열과 동일하게 가능함. cout << score[2] << endl; // 결과값 : 78
-
6. 벡터 대표 예제
#include <iostream> #include <vector> using namespace std; int main(void) { vector<int> fibonacci{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89}; for (auto &number : fibonacci) { cout << number << ' '; } cout << endl; return 0; }
7. push_back()과 pop_back()
- push_back()은 공백 벡터에서 시작하여서 하나씩 추가될 때마다 벡터의 크기를 확대한다.
- push_back() 사진 추가
- pop_back()은 push_back()과 반대 기능을 하는 함수이다.
- 벡터의 끝에서 요소를 제거하고 벡터의 크기를 하나 감소한다.
- 요소를 반환하지 않음으로 삭제하기 전에 미리 삭제할 요소를 다른 곳에 저장해야 한다. (파이썬과 다른 점)
- pop_back() 사진 추가
- 아래 예제 2개를 통해서 를 통해 확인해보자.
#include <iostream> #include <vector> using namespace std; int main(void) { vector<int> v1; v1.push_back(10); v1.push_back(20); v1.push_back(30); v1.push_back(40); v1.push_back(50); cout << "v1 = "; for (auto& e : v1){ cout << e << " "; } cout << endl; return 0; }
#include <iostream>
#include <vector>
using namespace std;
int main(void) {
vector<int> v;
for (int i = 0; i < 10; i++) {
v.push_back(i);
}
cout << "현재의 v = ";
for (auto &e : v)
cout << e << " ";
cout << endl;
cout << "삭제 요소 = ";
// 벡터가 공백이 될 때까지 pop_back() 호출
while (v.empty() != true) {
cout << v.back() << " ";
v.pop_back();
}
cout << endl;
return 0;
}
8. 벡터에서 요소의 위치 : v.begin() / v.end() / v.front() / v.back()
- 벡터에서 요소의 위치는 반복자(iterator)를 이용하여 표시한다.
- v.begin()은 벡터의 시작 주소, v.end()는 벡터의 마지막 주소를 가리킨다.
- v.front()는 벡터의 첫 번째 요소, v.back()는 벡터의 마지막 요소를 반환한다.
- v.begin()으로 식별되는 요소는 시퀀스의 일부이지만, v.end()는 시퀀스의 끝을 하나 넘는 요소이니 주의하자.
- 반복자가 중요한 이유는 벡터 안의 요소들을 가리킬 수 있기 때문이다.
for(auto p = v.begin(); p != v.end(); ++p)
cout << *p << endl;
// p는 포인터값, *p는 실제 값
9. 벡터의 중간 부분을 삭제하기 : erase()
- 벡터는 동적 배열이기 때문에 배열의 중간에서 요소를 삭제할 수 있다.
- 위의 그림과 같이 중간에 있는 벽돌이 공에 의해 충돌하게 되면 우리는 벡터의 중간에서 삭제해야 한다.
- 이 때 사용되는 함수는 erase() 함수이다.
- 삭제하려는 요소의 인덱스가 i라고 한다면 아래의 코드 문장으로 i번째 요소를 삭제할 수 있다.
v.erase(v.begin() + i);
10. 벡터와 연산자
- std::vector에서 == 연산자는 요소 단위로 비교하지 않는다. 대신 두 벡터가 같은 메모리를 가리키는지를 비교한다.
- 두 벡터가 같은지 확인하려면 == 연산자를 사용할 수 있지만, 이것은 두 벡터의 메모리 주소가 같은지를 비교하는 것이며, 벡터 내의 요소 값이 같은지를 비교하는 것이 아니다.
- 때문에 정확한 요소 단위 비교를 위해서는 별도의 루프나 사용자 정의 함수를 통해 요소를 비교해야 한다.
#include <iostream>
#include <vector>
using namespace std;
int main(void) {
vector<int> v1{1, 2, 3, 4, 5};
vector<int> v2(v1); // 다른 벡터를 인수로 받아 초기화하는 생성자가 있을 것이다.
if(v1 == v2) {
cout << "2개의 벡터가 일치합니다." << endl;
}
return 0;
}
11. 벡터 예제
예제1 : 벡터에 문자열 저장하자
#include <iostream>
#include <vector>
using namespace std;
int main(void) {
vector<string> vec; // 벡터를 생성한다.
vec.push_back("MILK"); // 벡터의 끝에 자료를 저장한다.
vec.push_back("BREAD");
vec.push_back("BUTTER");
for(auto e: vec){
cout << " " << e;
}
cout << endl;
return 0;
}
예제2 : 벡터에 Circle 객체를 저장하자
#include <iostream>
#include <vector>
using namespace std;
class Circle{
public:
int x, y;
int radius;
Circle() : x{0}, y{0}, radius{0}{}
Circle(int x, int y, int radius) : x{x}, y{y}, radius{radius}{}
void print() {
cout << "반지름: " << radius << " @(" << x << ", " << y << ")" << endl;
}
};
int main(void) {
vector<Circle> objArray;
for(int i = 0; i < 10; i++){
Circle obj{rand() % 300, rand() % 300, rand() % 100};
objArray.push_back(obj);
}
for (Circle c : objArray)
c.print();
return 0;
}
예제3 : 벡터와 알고리즘(정렬)
- sort(배열의 시작점 주소, 배열의 끝점 주소, (선택)) 함수 : 기본적으로 오름차순 정렬
- (선택)에다가 compare 함수를 만들어서 sort()의 세 번째 인자 값으로 넣게 되면, 해당 함수의 반환 값에 맞게 정렬이 동작된다.)
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
class Person{
private:
string name;
int age;
public:
Person(string n, int a){
name = n;
age = a;
}
string get_name() {return name;}
int get_age() {return age;}
void print(){
cout << name << " " << age << endl;
}
};
bool compare(Person &p, Person &q){
return p.get_age() < q.get_age();
}
int main(void) {
vector<Person> list;
list.push_back(Person("Kim", 30));
list.push_back(Person("Park", 22));
list.push_back(Person("Lee", 26));
sort(list.begin(), list.end(), compare);
for(auto& e : list){
e.print();
}
return 0;
}
예제4 : 성적평균을 계산하자
- 학생들의 평균 성적을 계산하는 예제에서 학생이 몇 명인지 알 수 없다고 하자. 동적 배열인 벡터를 이용하여서 작성해보자.
- Tip) 공백 벡터를 선언하고 사용자가 -1을 입력할 때까지 push_back() 함수를 호출하여 벡터에 성적을 추가한다. 입력이 종료되면 범위 기반 for 루프를 이용하여서 벡터에서 요소를 하나씩 꺼내서 평균을 계산한다.
- 결과 코드
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
int main(void) {
vector<int> scores;
int score;
int sum = 0;
double avg;
while (true) {
cout << "성적을 입력하시오(종료는 -1) : ";
cin >> score;
if (score == -1) {
break;
}
scores.push_back(score);
}
for(auto& s : scores){
sum += s;
avg = sum / scores.size();
}
cout << "성적 평균=" << avg << endl;
return 0;
}
예제5 : 영화정보를 저장하자
- 벡터를 이용하여 영화에 대한 정보를 저장했다가 출력하는 프로그램을 작성해보자.
- 정답 코드
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Movie {
private:
string title;
double rating;
public:
Movie(string t = "", double r = 0.0) {
title = t;
rating = r;
}
void print_movie() { cout << title << ": " << rating << endl; }
};
int main(void) {
vector<Movie> movies;
movies.push_back(Movie("titinic: ", 9.9));
movies.push_back(Movie("gone with the wind: ", 9.6));
movies.push_back(Movie("terminator: ", 9.7));
for (auto &m : movies) {
m.print_movie();
}
return 0;
}
12. array 클래스
- vector는 생성과 소멸을 하는데 상당한 시간이 소요된다. 따라서 vector의 장점이 많지만 성능 때문에 기존의 배열을 사용하는 경우도 많다.
- 이 문제를 해결하기 위해 C++11 에서는 std::array를 새롭게 제시하였다.
- array 클래스를 사용하면 벡터의 장점과 기존 배열의 성능을 동시에 누릴 수가 있다.(C++에서는 항상 성능(속도)를 중요시한다.)
- array 클래스는 기존의 배열보다 다양한 함수를 제공한다.
- size() : 배열의 크기
- fill() : 배열의 모든 원소를 동일한 값으로 채움
- empty() : 배열이 비어있는지 검사
- at() : 배열의 요소에 접근할 때 사용
- front() : 배열의 첫 번째 요소
- back() : 배열의 마지막 요소
- array 클래스 예제
-
#include <iostream> #include <array> using namespace std; int main(){ array<int, 3> list{1, 2, 3}; for (int i = 0; i < list.size(); i++){ ++list[i]; } for (auto& elem : list) cout << elem << " "; cout << endl; return 0; }
'Develop > C, C++' 카테고리의 다른 글
[C/C++] 객체 지향 프로그래밍과 클래스 (0) | 2023.12.25 |
---|---|
[C/C++] 생성자(constructor) & 접근 제어(access control) (0) | 2023.12.23 |
[C/C++] 상속(Inheritance) (0) | 2023.12.19 |
[C/C++] 동적할당(Dynamic Memory Allocation) (0) | 2023.12.18 |
[C/C++] 문자열(String) (0) | 2023.12.18 |