본문 바로가기
Programming/C++

[C++] 6. 객체 배열과 벡터

by Lizardee 2024. 1. 30.
6.1 이번 장에서 만들어 볼 프로그램

6.2 객체 배열

: 객체들이 모여 있는 컨테이너

#include <iostream>
#include <stdlib.h>
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() {
	Circle objArray[10];  // 객체 배열

	srand(time(NULL));
	for (Circle& c : objArray) {
		c.x = rand() % 500;
		c.y = rand() % 500;
		c.radius = rand() % 100;
	}

	for (Circle& c : objArray) {
		c.print();
	}

	return 0;
}

여러 권의 책을 저장해보자
#include <iostream>
#include <string>
using namespace std;

class Book {
public:
	string title;
	int price;

	Book(string t, int p) {
		title = t;
		price = p;
	}

	void print() {
		cout << "제목: " << title << ",     가격: " << price << endl;
	}
};

int main() {
	// 객체 배열
	Book books[2] = {
		Book("어서와 C++", 30000),
		Book("어서와 C", 22000)
	};

	cout << "소장하고 있는 책 정보" << endl;
	cout << "================================" << endl;
	for (Book& b : books)
		b.print();
	cout << "================================" << endl;

	return 0;
}


6.3 벡터

이제까지 우리가 학습한 배열은 정적 배열이다. 즉, 컴파일 시간에 배열의 크기가 결정되고, 더 이상 크기의 변경은 불가능하다.

C++에서는 실행 시간에 크기를 변경할 수 있는 동적 배열(dynamic array)도 제공한다. 이것은 벡터(vector)라고 불리며, 라이브러리로 제공된다.

/* 벡터 선언 */
vector<int> scores(10);  // 배열의 자료형, 배열의 이름, 배열의 크기

피보나치: 벡터

 

▶ push_back()과 pop_back()

: 정적 배열을 사용하는데 가장 문제점은 저장되는 데이터의 개수를 미리 알지 못한다는 것이다.

예를 들어, 성적 평균을 계산하는 프로그램에서도 학원생들이 수시로 등록하거나 취소하기 때문에 학원생이 몇 명인지 알 수 없다고 하자.

  • push_back(): 공백 벡터에서 시작하여서 성적이 하나씩 추가될 때마다 벡터의 크기를 확대한다.

#include <vector>
#include <iostream>
using namespace std;

int main(void) {
	vector<int> v1;

	// push_back
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);
	v1.push_back(40);
	v1.push_back(50);

	cout << "v1 = ";
	for (auto& v : v1)
		cout << v << " ";
	
	return 0;
}

 

  • pop_back(): 벡터의 끝에서 요소를 제거하고, 벡터의 크기를 하나 감소시킨다. 한가지 주의할 점은, pop_back()은 요소를 반환하지 않는다. 따라서 삭제하기 전에 미리 삭제할 요소를 다른 곳에 저장하여야 한다.

#include <vector>
#include <iostream>
using namespace std;

int main(void) {
	vector<int> v;

	// push_pack()
	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;
}

 

▶ 벡터에서 요소의 위치

: 벡터에서 요소의 위치는 반복자(iterator)를 이용하여 표시한다.

 

▶ 중간에서 삭제하는 방법

: 중간에서 삭제하려면 삭제하려는 요소의 인덱스를 알아야 한다.

  • v.erase()
// 인덱스가 i인 요소 삭제
v.erase(v.begin()+i);

 

▶ 벡터와 연산자

벡터 복사하기

 

▶ 문자열을 저장해보자.

: 객체 배열은 전통적인 방식으로 만들 수도 있지만, 벡터(vector 클래스)를 이용하여 동적인 객체 배열을 만들 수도 있다. 

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main(void) {
	vector<string> v;

	v.push_back("MILK");
	v.push_back("BREAD");
	v.push_back("BUTTER");
	for (auto& c : v)
		cout << c << " ";
	cout << endl;

	return 0;
}

 

▶ Circle 객체를 저장해보자.

vector<Circle> objArray;

#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 r) {
		x = _x;
		y = _y;
		radius = r;
	}

	void print() {
		cout << "반지름: " << radius << " @(" << x << ", " << y << ")" << endl;
	}
};

int main() {
	vector<Circle> objArray;  // Circle 객체 저장

	for (int i = 0; i < 10; i++) {
		Circle obj{ rand() % 300, rand() % 300, rand() % 100 };
		objArray.push_back(obj);  // obj을 push_back
	}

	for (Circle c : objArray)
		c.print();

	return 0;
}

 

▶ 벡터와 알고리즘

: 우리가 벡터를 사용하는 중요한 이유 중의 하나는 편리한 STL 알고리즘을 사용할 수 있기 때문이다. 

예를 들어, 우리는 벡터 안의 요소들을 어떤 기준에 의하여 정렬시킬 수 있다.

  • bool compare()
  • sort()
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;

class Person {
public:
	string name;
	int age;

	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;
	}
};

// Person 객체들을 나이순으로 정렬하는 비교 함수
bool compare(Person& p, Person& q) {
	return p.get_age() < q.get_age();
}

int main() {
	vector<Person> list;

	list.push_back(Person("Kim", 30));
	list.push_back(Person("Park", 22));
	list.push_back(Person("Lee", 26));

	// sort(정렬)
	sort(list.begin(), list.end(), compare);

	for (auto& l : list)
		l.print();

	return 0;
}

성적 평균 계산하기
#include <iostream>
#include <vector>
using namespace std;

int main() {
	vector<int> score;
	int sum = 0;
	int i = 0;

	while (1) {
		int input;
		cout << "성적을 입력하시오(종료는 -1) : ";
		cin >> input;
		if (input == -1)
			break;
		score.push_back(input);
		i++;
	}

	for (auto& e : score)
		sum += e;

	cout << "성적 평균=" << sum / i << endl;

	return 0;
}

score.push_back(input);


영화 정보 저장
#include <iostream>
#include <vector>
using namespace std;

class Movie {
public:
	string title;
	double score;

	Movie(string t, double s) {
		title = t;
		score = s;
	}

	void print() {
		cout << title << ": " << score << endl;
	}
};

int main() {
	vector<Movie> myMovie;

	myMovie.push_back(Movie("타이타닉", 9.9));
	myMovie.push_back(Movie("바람과 함께 사라지다", 9.6));
	myMovie.push_back(Movie("터미네이터", 9.7));

	for (auto& e : myMovie)
		e.print();

	return 0;
}


6.4 array 클래스
  • vector: 생성과 소멸을 하는데 상당한 시간이 소요된다. 따라서 vector의 장점이 많지만 성능때문에 기존의 배열을 사용하는 경우도 많다.

이 문제를 해결하기 위해 c++11에서는 std::array를 새롭게 제시하였다.

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& e : list)
		cout << e << " ";
	cout << endl;

	return 0;
}
  • size(): 배열의 크기
  • fill(): 배열의 모든 원소를 동일한 값으로 채운다.
  • empty(): 배열이 비어있는지 검사한다.
  • at(): 배열의 요소에 접근할 때 사용된다. ([] 기호를 사용해도 됨)
  • front(): 배열의 첫 번째 요소
  • back(): 배열의 마지막 요소