문제

 

 

풀이

세 정수를 받아 피타고라스의 정리를 이용해 직각삼각형인지 판별하고, 0 0 0이 입력되면 반복문이 종료되도록 한다.

#include <iostream>

using namespace std;

int main() {
	int x, y, z;
	int tmp;

	while (true) {
		cin >> x >> y >> z;

		if ((x == 0) && (y == 0) && (z == 0)) break;

		if (x > y) {
			tmp = y;
			y = x;
			x = tmp;
		}

		if (y > z) {
			tmp = z;
			z = y;
			y = tmp;
		}

		if (x * x + y * y == z * z) cout << "right\n";
		else cout << "wrong\n";
	}

	return 0;
}

'백준 > 기타' 카테고리의 다른 글

2609번: 최대공약수와 최소공배수 [C++]  (0) 2023.04.06
1259번: 팰린드롬수 [C++]  (0) 2023.04.06
15829번: Hashing [C++]  (0) 2023.04.06
2903번: 중앙 이동 알고리즘 [C++]  (0) 2023.04.03
2720번: 세탁소 사장 동혁 [C++]  (0) 2023.04.03

복사 생성자(Copy Constructor)

다음과 같은 생성자를 '복사 생성자(Copy Constructor)'라 한다.

Simple(const Simple &copy) : num1(copy.num1), num2(copy.num2) {
	cout << "Called Simple(Simple &copy)" << endl;
}

 

디폴트 복사 생성자

 복사 생성자의 삽입 없이도 멤버 대 멤버의 복사가 진행 가능하며 이것은 복사 생성자를 정의하지 않으면, 멤버 대 멤버의 복사를 진행하는 디폴트 복사 생성자가 자동으로 삽입되기 때문이다.

이 때문에 많은 경우에서는 복사 생성자를 따로 정의하지 않아도 된다.

 

explicit

 explicit 키워드를 이용해 복사 생성자의 묵시적 호출을 허용하지 않을 수도 있다.

explicit Simple(const Simple &copy) : num1(copy.num1), num2(copy.num2) {
	
}

 이렇게 될 경우 묵시적 변환이 발생하지 않아 아래와 같이 대입 연산자를 이용한 객체의 생성 및 초기화가 불가능해진다.

  • Simple simple1 = simple2;

 

'깊은 복사'와 '얕은 복사'

 디폴트 복사 생성자는 멤버 대 멤버의 복사를 진행하고, 이러한 방식의 복사를 가리켜 '얕은 복사(Shallow Coply)'라 한다. 이는 멤버변수가 힙의 메모리 공간을 참조하는 경우에 문제가 발생한다.

 

디폴트 복사 생성자의 문제점

 하나의 문자열을 두 개의 객체가 동시에 참조하는 것과 같은 경우, 객체의 소멸 과정에서 하나의 객체가 먼저 소멸된 뒤, 남아있는 객체가 소멸될 시 이미 지워진 문자열을 대상으로 delete 연산을 하기 때문에 문제가 발생한다.


'깊은 복사'를 위한 복사 생성자의 정의

 다음과 같이 복사 생정자를 정의하면, 객체 별로 각각의 문자열을 참조하기 때문에 객체의 소멸 과정에서 문제가 발생하지 않는다. 

Person(const Person& copy) : age(copy.age) {
	name = new char[strlen(copy.name) + 1];
    strcpy(name, copy.name);
}

 위의 생성자가 하는 일은 다음 두 가지이다.

  • 멤버변수 age의 멤버 대 멤버 복사
  • 메모리 공간 할당 후 문자열 복사, 그리고 할당된 메모리의 주소 값을 멤버 name에 저장

이러한 형태의 복사를 가리켜 '깊은 복사(Deep Copy)'라 한다.

 

복사 생성자의 호출시점

 복사 생성자가 호출되는 시점은 크게 아래 세 가지로 구분할 수 있다.

  • 기존에 생성된 객체를 이용해서 새로운 객체를 초기화하는 경우
  • Call-by-value 방식의 함수호출 과정에서 객체를 인자로 전달하는 경우
  • 객체를 반환하되, 참조형으로 반환하지 않는 경우

 이것들은 모두 객체를 새로 생성하며, 생성과 동시에 동일한 자료형의 객체로 초기화해야 한다는 공통점이 있다.

이를 설명하기 위해 설명할 메모리 공간이 할당과 동시에 초기화 되는 상황들은 아래와 같다.

  • int n1 = n2;
  • Func(n); // 호출되는 순간 매개변수가 할당과 동시에 초기화
  • return n; // 반환하는 순간 메모리 공간이 할당되면서 동시에 초기화

이러한 상황은 객체를 대상으로 해도 달라지지 않으며, 위 복사 생성자 호출 시점에 각각 대응됨을 알 수 있다.

 

임시객체(Temporary Object)

 객체의 반환 시, 임시객체라는 것이 생성되고 임시객체의 참조 값이 반환된다. 그리고 임시객체는 참조자에 의해 참조되지 않는 다면 다음 행으로 넘어가면서 즉시 소멸된다.

'개인 공부 > C++' 카테고리의 다른 글

[C++] Chapter 06 정리  (0) 2023.04.10
[C++] Chapter 04 정리  (0) 2023.03.29
[C++] Chapter 03 정리  (0) 2023.03.28
[C++] Chapter 02 정리  (0) 2023.03.23
[C++] Chapter 01 정리  (0) 2023.03.22

문제

 

 

풀이

주어진 조건대로 n번 거쳤을 때 점의 총 개수는 아래 표와 같다.

n = 0 n = 1 n = 2 n = 3 n = 4 ...
2 x 2 3 x 3 5 x 5 9 x 9 17 x 17 ...

위 표를 통해 (1 + 2n) x (1 + 2n)의 규칙이 있음을 알 수 있다.

#include <iostream>
#include <string>

using namespace std;

int main() {
	int n;
	int num = 1;

	cin >> n;

	num <<= n;

	cout << (1 + num) * (1 + num);

	return 0;
}

'백준 > 기타' 카테고리의 다른 글

2609번: 최대공약수와 최소공배수 [C++]  (0) 2023.04.06
1259번: 팰린드롬수 [C++]  (0) 2023.04.06
15829번: Hashing [C++]  (0) 2023.04.06
4153번: 직각삼각형 [C++]  (0) 2023.04.06
2720번: 세탁소 사장 동혁 [C++]  (0) 2023.04.03

문제

 

 

풀이

#include <iostream>
#include <string>

using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int t;

	cin >> t;

	for (int i = 0; i < t; i++) {
		int c;
		int quarter = 0, dime = 0, nickel = 0, penny = 0;

		cin >> c;

		quarter = c / 25;
		c %= 25;

		dime = c / 10;
		c %= 10;

		nickel = c / 5;
		c %= 5;

		penny = c / 1;
		c %= 1;

		cout << quarter << ' ' << dime << ' ' << nickel << ' ' << penny << '\n';
	}

	return 0;
}

'백준 > 기타' 카테고리의 다른 글

2609번: 최대공약수와 최소공배수 [C++]  (0) 2023.04.06
1259번: 팰린드롬수 [C++]  (0) 2023.04.06
15829번: Hashing [C++]  (0) 2023.04.06
4153번: 직각삼각형 [C++]  (0) 2023.04.06
2903번: 중앙 이동 알고리즘 [C++]  (0) 2023.04.03

문제

 

 

풀이

n + m번 동안 문자열을 받으며 value가 1보다 크면 듣보잡이기 때문에 해당 조건을 만족하는 문자열들을 따로 배열에 담은 후, 배열의 크기를 출력하고, 원소들을 사전순으로 출력하면 된다.

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

int main() {
	ios_base::sync_with_stdio(false); 
	cin.tie(NULL); 
	cout.tie(NULL);

	int n, m;
	string s;

	map<string, int> mp;
	vector<string> result;

	cin >> n >> m;

	for (int i = 0; i < n + m; i++) {
		cin >> s;

		mp[s]++;
		if (mp[s] > 1)
			result.push_back(s);
	}

	sort(result.begin(), result.end());

	cout << result.size() << "\n";

	for (int i = 0; i < result.size(); i++)
		cout << result[i] << "\n";

	return 0;
}

'백준 > 집합과 맵' 카테고리의 다른 글

10816번: 숫자 카드 2 [C++]  (0) 2023.03.31
1620번: 나는야 포켓몬 마스터 이다솜 [C++]  (0) 2023.03.31
14425번: 문자열 집합 [C++]  (0) 2023.03.31
10815번: 숫자 카드 [C++]  (0) 2023.03.31

문제

 

 

풀이

#include <iostream>
#include <unordered_map>

using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int n, num;
	unordered_map<int, int> m;

	cin >> n;

	for (int i = 0; i < n; i++) {
		cin >> num;

		m[num]++;
	}

	cin >> n;

	for (int i = 0; i < n; i++) {
		cin >> num;

		cout << m[num] << " ";
	}

	return 0;
}

'백준 > 집합과 맵' 카테고리의 다른 글

1764번: 듣보잡 [C++]  (0) 2023.03.31
1620번: 나는야 포켓몬 마스터 이다솜 [C++]  (0) 2023.03.31
14425번: 문자열 집합 [C++]  (0) 2023.03.31
10815번: 숫자 카드 [C++]  (0) 2023.03.31

문제

아래 링크 참고

 

1620번: 나는야 포켓몬 마스터 이다솜

첫째 줄에는 도감에 수록되어 있는 포켓몬의 개수 N이랑 내가 맞춰야 하는 문제의 개수 M이 주어져. N과 M은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수인데, 자연수가 뭔지는 알지? 모르면

www.acmicpc.net

 

 

풀이

<이름, 번호>와 <번호, 이름> 구조의 맵을 따로 만들어서 이름이 들어오면 번호, 번호가 들어오면 이름을 출력하도록 하였다.

#include <iostream>
#include <string>
#include <map>

using namespace std;

int main() {
	ios_base::sync_with_stdio(false); 
	cin.tie(NULL); 
	cout.tie(NULL);

	int n, m;
	int cnt = 1;
	map<string, int> pokemonNum;
	map<int, string> pokemonName;

	cin >> n >> m;

	for (int i = 0; i < n; i++) {
		string s;

		cin >> s;

		pokemonNum[s] = cnt + i;
		pokemonName[cnt + i] = s;
	}

	for (int i = 0; i < m; i++) {
		string s;

		cin >> s;

		if (s[0] >= 'A' && s[0] <= 'Z')
			cout << pokemonNum[s] << "\n";
		else
			cout << pokemonName[stoi(s)] << "\n";
	}

	return 0;
}

'백준 > 집합과 맵' 카테고리의 다른 글

1764번: 듣보잡 [C++]  (0) 2023.03.31
10816번: 숫자 카드 2 [C++]  (0) 2023.03.31
14425번: 문자열 집합 [C++]  (0) 2023.03.31
10815번: 숫자 카드 [C++]  (0) 2023.03.31

문제

 

 

풀이

map 자료구조를 사용해 풀면된다.

#include <iostream>
#include <string>
#include <map>

using namespace std;

int main() {
	int n, m;
	int cnt = 0;
	map<string, bool> mp;

	cin >> n >> m;

	for (int i = 0; i < n; i++) {
		string s;

		cin >> s;

		mp.insert({ s, true });
	}

	for (int i = 0; i < m; i++) {
		string s;

		cin >> s;

		if (mp[s] == true) cnt++;
	}

	cout << cnt;

	return 0;
}

'백준 > 집합과 맵' 카테고리의 다른 글

1764번: 듣보잡 [C++]  (0) 2023.03.31
10816번: 숫자 카드 2 [C++]  (0) 2023.03.31
1620번: 나는야 포켓몬 마스터 이다솜 [C++]  (0) 2023.03.31
10815번: 숫자 카드 [C++]  (0) 2023.03.31

문제

 

 

풀이

시간초과에 주의하자

#include <iostream>
#include <unordered_map>

using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int n, num;
	unordered_map<int, int> m;

	cin >> n;

	for (int i = 0; i < n; i++) {
		cin >> num;

		m[num]++;
	}

	cin >> n;

	for (int i = 0; i < n; i++) {
		cin >> num;

		cout << m[num] << " ";
	}

	return 0;
}

'백준 > 집합과 맵' 카테고리의 다른 글

1764번: 듣보잡 [C++]  (0) 2023.03.31
10816번: 숫자 카드 2 [C++]  (0) 2023.03.31
1620번: 나는야 포켓몬 마스터 이다솜 [C++]  (0) 2023.03.31
14425번: 문자열 집합 [C++]  (0) 2023.03.31

정보은닉(Information Hiding)

좋은 클래스가 되기 위한 최소한의 조건은 '정보은닉'과 '캡슐화'이다.

 

 멤버변수가 public으로 선언된다면 어디서든 접근이 가능해지기 때문에 문제가 발생할 수 있다.

 이러한 문제를 막기 위해 제한된 방법으로의 접근만 허용하여 잘못된 값이 저장되지 않도록 해야하며, 또한 실수가 쉽게 발견될 수 있도록 해야한다.

class Car {
private:
	int fuel;
    int speed;
public:
	void InitCarState(int fuel, int speed);
    int GetFuel() const;
    bool SetFuel(int fuel);
    void Accel();
};

 

 이렇게 멤버변수를 private으로 선언하고, 해당 변수에 접근하는 함수를 별도로 정의해서, 안전한 형태로 멤버변수의 접근을 유도하는 것이 '정보은닉'이다.

 

 위의 코드에서 아래와 같이 'Get멤버변수명', 'Set멤버변수명'으로 정의된 함수들을 '액세스 함수(Access Function)'라 하며 이러한 액세스 함수들은 멤버변수를 private으로 선언하면서 클래스 외부에서 멤버변수로의 접근을 목적으로 정의되는 함수들이다.

int GetFuel() const;
bool SetFuel(int fuel);

 추가로 앞에서 선언된 함수에 const 선언이 추가되어 있는 경우가 있는데, 이는 해당 함수 내에서는 멤버변수에 저장된 값을 변경하지 않겠다는 의미이다. 또한 이렇게 선언 시 const 함수 내에서는 const가 아닌 함수의 호출이 제한됨으로써 코드의 안정성을 높일 수 있다.

 

 

캡슐화(Encapsulation)

 정보은닉과 함께 객체지향 기반의 클래스 설계에서 가장 기본이면서도 중요한 원칙들이다.

 

 캡슐화를 하게 되면 상호관계가 복잡했던 것을 줄일 수 있게 되고 프로그램을 간결하게 만들 수 있으나 캡슐화의 범위를 결정하는 일이 쉽지 않기 때문에 어려운 개념이기도 하다. 그렇기 때문에 다양한 사례를 접하며 클래스를 캡슐화 시키는 능력을 기를 필요가 있다.

 

 

생성자(Constructor)와 소멸자(Destructor)

 지금까지 멤버함수를 통해 멤버변수를 초기화 시켰지만, '생성자'를 이용해 객체를 생성과 동시에 초기화할 수 있다.

class SimpleClass {
private:
    int num;
public:
    SimpleClass(int n) { // 생성자(Constructor)
        num = n;
    }
    int GetNum() const {
        return num;
    }
};

 

 위의 클래스에서 클래스의 이름과 함수의 이름이 동일하고, 반환형이 선언되어 있지 않고, 실제로 반환하지 않는 함수가 있다. 이러한 유형의 함수를 가리켜 '생성자(Constructor)'라 하며, 이 함수는 개체 생성시 딱 한 번 호출된다. 

 

 생성자 또한 함수의 일종이므로 오버로딩이 가능하며, 매개변수의 디폴트 값 설정도 가능하다.

class SimpleClass {
public:
	int num1;
	int num2;
private:
	SimpleClass() {
		num1 = 0;
		num2 = 0;
	}
	SimpleClass(int n) {
		num1 = n;
		num2 = 0;
	}
	SimpleClass(int n1, int n2) {
		num1 = n1;
		num2 = n2;
	}
};

 

위에서 정의된 생성자를 통해 객체를 생성하려면 아래와 같이 문장이 구성된다.

  • SimpleClass sc2(100);
  • SimpleClass * ptr2 = new SimpleClass(100);
  • SimpleClass sc3(100, 200);
  • SimpleClass * ptr3 = new SimpleClass(100, 200);

그러나 아래와 같은 문장은 허용되지 않는다.

  • SimpleClass sc1();

대신 아래와 같이 구성해야 한다.

  • SimpleClass sc1;
  • SimpleClass * ptr1 = new SimpleClass;
  • SimpleClass * ptr1 = new SImpleClass();

 이는 main 함수내에서 Simpleclass sc();와 같은 문장이 선언되면 객체를 생성하기 위한 객체생성문인지 함수의 원형선언인지 구분할 수 없기 때문에 C++에서는 이를 함수의 원형선언에만 사용하기로 약속하였다.

 

 

멤버 이니셜라이저(Member Initializer)

 

  객체의 생성과정에서 그 객체의 멤버변수로 선언된 객체의 생성자를 호출하여 멤버변수로 선언된 객체를 초기화할 수 있으며 이에 사용되는 것이 '멤버 이니셜라이저(Member Initializer)'이다.

class Rectangle {
private:
	Point upLeft;
    Point lowRight;
public:
	Rectangle(cont int &x1, const int &y1, const int &x2, const int &y2);
    void ShowRecInfo() const;
};
Rectangle::Rectangle(cont int &x1, const int &y1, const int &x2, const int &y2):upLeft(x1, y1), lowRight(x2, y2) {
	//Empty
}

 

 위 코드에서 :upLeft(x1, y1), lowRight(x2, y2)에 해당하는 부분이 '멤버 이니셜라이저'이며 이것은 아래의 의미를 가진다.

  • 객체 upLeft의 생성과정에서 x1, y1을 인자로 전달받는 생성자를 호출
  • 객체 lowRight의 생성과정에서 x2, y2를 인자로 전달받는 생성자를 호출

 멤버 이니셜라이저를 사용하다 보면, 생성자의 몸체가 비어있는 경우가 발생하나 그냥 무시하면 된다.

 

 멤버 이니셜라이저는 객체가 아닌 멤버의 초기화에서도 사용할 수 있으며 아래와 같은 두 가지 장점이 있기 때문에 이니셜라이저를 통해 멤버번수를 초기화 하는 것이 선호된다.

  • 초기화의 대상을 명확히 인식할 수 있다.
  • 성능에 약간의 이점이 있다.

 또한, 이니셜라이저를 이용하면 선언과 동시에 초기화가 이뤄지는 형태로 바이너리 코드가 생성되므로 const 멤버변수도이니셜라이저를 통해 초기화가 가능하며 이러한 특징은 멤버변수로 참조자를 선언할 수 있게 한다.

 

 

디폴트 생성자(Default Constructor)

 객체가 생성되기 위해서는 반드시 하나의 생성자가 호출되어야 한다. 이를 위해 생성자를 정의하지 않은 클래스에는 C++ 컴파일러에 의해 디폴트 생성자라는 것이 자동으로 삽입된다.

 

private 생성자

 객체의 생성이 클래스의 외부에서 진행되면 생성자는 public으로 선언되어야 한다. 하지만 클래스 내부에서 객체를 생성한다면, private으로 선언될 수 있다.

 

소멸자의 이해와 활용

 객체 생성 시 반드시 호출되는 것이 생성자라면, 객체 소멸 시 만드시 호출되는 것을 소멸자라 하고, 아래와 같은 형태를 갖는다.

  • 클래스의 이름 앞에 '~'가 붙은 형태의 이름을 갖는다.
  • 반환형이 선언되어 있지 않으며, 실제로 반환하지 않는다.
  • 매개변수는 void형으로 선언되어야 하기 때문에 오버로딩도, 디폴트 값 설정도 불가능하다.

 소멸자도 생성자와 마찬가지로 소멸자가 정의되어 있지 않으면 디폴트 소멸자가 자동으로 삽입된다.

 

 소멸자는 대체로 생성자에서 할당한 리소스의 소멸에 사용되며, 생성자에서 new 연산자를 이용해 할당해 놓은 메모리 공간이 있다면, 소멸자에서는 delete 연산자를 이용해서 메모리 공간을 소멸한다.

 

 

클래스와 배열 그리고 this 포인터

객체 배열

 객체 기반의 배열은 다음의 형태로 선언한다.

  • SimpleClass arr[10];
  • SimpleClass * ptrArr = new SimpleClass[10];

this 포인터

 멤버함수 내에서는 this라는 이름의 포인터를 사용할 수 있고, 이는 객체 자신을 가리키는 용도로 사용되는 포인터이다.

class SimpleClass {
private:
	int num;
public:
	SimpleClass * GetThisPointer( {
    	return this;
    }
    void ThisFunc(int num) {
    	this->num = 200;
        num = 100;
    }
};

 

 이러한 특성을 이용해 멤버변수와 매개변수의 이름을 동일하게 짓고, this 포인터를 이용해서 이 둘을 구분하기도 한다.

 

Self-Reference의 반환

 Self-Reference란 객체 자신을 참조할 수 있는 참조자를 의미하며, this 포인터를 이용해 객체가 자신의 참조에 사용할 수 있는 참조자의 반환문을 구성할 수 있다.

 

참조의 정보(참조 값)에 대한 이해

int main() {
	int num = 7;
    int &ref = num;
    ...

 이것은 다음과 같이 표현하기도 한다.

"변수 num을 참조할 수 있는 참조 값이 참조자 ref에 전달되어, ref가 변수 num을 참조하게 된다."

'개인 공부 > C++' 카테고리의 다른 글

[C++] Chapter 06 정리  (0) 2023.04.10
[C++] Chapter 05 정리  (0) 2023.04.05
[C++] Chapter 03 정리  (0) 2023.03.28
[C++] Chapter 02 정리  (0) 2023.03.23
[C++] Chapter 01 정리  (0) 2023.03.22

+ Recent posts