주의 : 이 글은 C의 기초문법에 대해 상세하게 다루지 않습니다. (즉 C언어에서 배울 수 있는 기초내용은 생략합니다)
※ 명품 C++ Programming 의 책을 참고하여 개인적으로 정리한 글입니다.
이 글의 목적은 해당 책의 내용을 인용하여 더 쉽게 이해하고자 정리하고, 더 쉬운 예제를 통해 이해하는 것을 목표로 하고 있습니다.
명품 C++ Programming의 예제문제와 실습문제가 정말 좋으므로, 깊게 공부하고 싶다면 책을 구매하는 것을 추천드립니다.
책의 저작권 등등 각종 권한은 출판사와 지은이/옮긴이에 있습니다.
- 출판사: (주)생능 출판사
- 지음: 황기태
C++ 언어의 기초 뼈대
다음의 코드를 보시겠습니다.
#include<iostream>
using namespace std;
int main() {
int t;
cin >> t;
cout << t;
}
C++의 가장 기본적인 뼈대입니다. iostream은 C언어의 stdio 와 같은 라이브러리입니다. 기본적인 화면출력 동작들을 내장하고 있는 라이브러리 입니다. cin의 경우 입력을 받는 것이고, cout의 경우 출력을 하는 것입니다.
여기서 using namaspce std의 경우를 살펴보면 원래 코드는 이런식으로 작성됩니다.
#include<iostream>
int main() {
int t;
std::cin >> t;
std::cout << t;
}
using namaspce std에서 이름공간(namespace)란 무엇인가
이름공간(namespace)은 std::cin 에서 std:: 부분을 이름공간이라고 부르는데, 쉽게 생각해서 어떠한 공간이라고 생각하면 편하다. 예를 들어 서울시의 김철수와 경기도의 김철수 이라면 두 사람의 이름은 같다. 그러나 사는 곳은 각각 다르다. 이처럼 이름공간은 사는 곳이라고 생각하면된다.
이러한 namespace의 개념이 필요한 이유는 1. 프로젝트를 여러 명이 나누어 개발할 때, 변수명이 같을 경우 문제가 발생한다. 2. 같은 사례로 누군가의 코드를 가져와서 사용할 때 변수명이 겹칠 우려가 있다.
그래서 개발자가 자신만의 이름공간을 만들어서 변수를 넣어둘 수 있게 하였다. 한가지 코드적 예시를 들어보자.
#include<iostream>
namespace my_su {
int one = 1;
int su() {
return 10000;
}
}
namespace kim_su {
int one = 2;
int su() {
return 20000;
}
}
int main() {
std::cout << my_su::su();
std::cout << std::endl;
std::cout << my_su::one;
std::cout << std::endl;
std::cout << kim_su::su();
std::cout << std::endl;
std::cout << kim_su::one;
}
my_su와 kim_su를 namespace로 분리하였을 때 변수명은 같으나 각각 선언된 namespace가 다르기 때문에
다음처럼 같은 변수를 출력해도 다르게 나타난다. 마찬가지로 endl이라는 변수도 std에 "\n" 과 같은 느낌으로 저장되어 있기 때문에 줄바꿈이 된다.
std 이름공간(namespace)의 생략
여튼 다시 본론으로 돌아와서
#include<iostream>
int main() {
int t;
std::cin >> t;
std::cout << t;
}
이 코드에서 std::를 계속해서 선언하는 것은 귀찮은 일이다. 그러니 다음을 입력하면 된다.
using namaspce std
이 경우 std를 생략해도 된다. (std로 선언된 모든 이름에 std::를 생략하겠다 라는 뜻이다)
하지만 이를 생략해야 하는가? 여기서 C++ 프로그래머들이 두 가지로 나뉜다. std를 생략하고 코딩을 하자는 사람들과 std를 생략하지 말고 코딩을 하자는 사람들로 나뉜다. 그래서 인터넷을 돌다보면 다양하게 C++로 코딩하는 사람들을 만난 수 있다.
그럴 때는 예시를 하나 보는게 좋은 방법일 수 있다. Robot Operating System 줄여서 ROS라고 불리는 이 놈을 작성할때는 C++ 언어가 사용된다. 이 예는 ROS에서 사용되는 코드 이며, ROS 세상에 토픽을 발행하는 코드이다.
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
/* This example creates a subclass of Node and uses std::bind() to register a
* member function as a callback from the timer. */
class MinimalPublisher : public rclcpp::Node
{
public:
MinimalPublisher()
: Node("minimal_publisher"), count_(0)
{
publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
private:
void timer_callback()
{
auto message = std_msgs::msg::String();
message.data = "Hello, world! " + std::to_string(count_++);
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
publisher_->publish(message);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
size_t count_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalPublisher>());
rclcpp::shutdown();
return 0;
}
그냥 어떻게 생긴 코드인지 보자고.
using namespace std::chrono_literals;
이 코드는 chrono_literals에 한해서만 std:: 를 생략하겠다는 뜻이다.
여튼 namespace 실전에서 정말 다양하게 활용된다. 이 것을 보여주고 싶었다.
std::cin >> t;
std::cout << t;
cin이 사용자로 부터 입력을 받아오는 것이고, cout이 출력을 하는 것이라는 것을 알았다. 그렇다면 <<와 >>의 의미는 무엇일까?
본래 >>와 <<의 뜻은 쉬프트연산(비트연산자) 라고 해서 이진수로 표현된 수를 오른쪽으로(>>)밀거나 왼쪽으로(<<)미는 역활을 하는 연산자이다.
그러나 C++에서는 이러한 연산자를 재정의 할 수 있다. 즉 나만의 + 연산을 만들 수 있다는 뜻이다. 그러면 cout 에서의 << 연산의 관계와 cin 에서의 >>의 의미는
cout에서 <<은 화면에 출력을 하게 하는 역할이고 cin 에서 >>는 사용자로 부터 입력을 받아가는 것으로 이해하면된다.
iostream 파일을 뜯어보면 istream 의 cin 이니 istream파일을 한 번 살펴보자.
>>를 검색하면 나온다. 여기서 operator가 연산자를 재정의 한 것이다. 여기서는 다양한 경우의 >> 연산자를 정의를 해놓았다. 이걸 해석하는데 까지 가면 더 높은 레벨의 C++ 스킬이 필요한 것으로 보인다. 공부가 끝나면 이정도 경지까지 올라가 보자고..
C++의 특징
C++에서는 변수를 아무 곳에서나 선언해도 문제가 발생하지 않는다.
#include<iostream>
int main() {
int one = 1;
std::cout << one << std::endl;
int two = 2;
std::cout << two;
}
옛날의 C언어에서는 안되었다는 모양
C++에서 문자열을 입력받기
원래 C에서는 string을 지원하지 않는다. 다른 언어를 배우고나서 C언어를 배우면 상당한 제약에 어려움을 겪는다.
그래서 C언어에서는 문자열을 선언할때 char형 배열로 선언을 했어야했다. C++에서도 이러한 방식의 문자열 입력이 가능하다.
#include<iostream>
int main() {
char hi[10] = "hello";
std::cout << hi;
}
또한 이상태로 문자열을 입력받을 수 있다.
#include<iostream>
int main() {
char hi[10];
std::cin >> hi;
std::cout << hi;
}
C++ 표준에서는 string의 여러 함수를 다루기 위해서는 cstring 해더파일을 사용하기를 권장한다. 이에 대한 설명은 후에 string에 대해서 다룰 때 자세히 살펴보도록 하자.
C++에서 공백이 포함된 문자열을 입력받기
C++에서 공백이 포함된 문자열을 입력받는 방법은 다음과 같다.
#include<iostream>
int main() {
char hi[10];
std::cin.getline(hi, 10, '\n');
std::cout << hi;
}
std::cin.getline(변수, 크기, 끝의 문자) 로 선언하면 된다.
공백을 포함해서 입력을 받는 모습을 보여준다.
C++ 주로 사용하는 방법은 #include <string>
위의 방법은 cin.getline을 간간히 입력할때를 제외하고는 주로 string 클래스를 사용한다.
#include <iostream>
#include <string>
int main() {
std::string hi("hi");
std::string hi2 = "hello";
std::cout << hi;
std::cout << hi2;
}
다음처럼 클래스의 instiation 형식으로 선언이 가능하고, 그냥 평소 변수를 선언하듯 만들 수 있다. 그리고 당연히 namespace std로 std:: 를 생략시킬 수도 있다.
또한 위에서의 getline으로 입력을 받을 수도 있다.
#include <iostream>
#include <string>
int main() {
std::string hi("hi");
std::string hi2 = "hello";
std::cout << hi;
std::cout << hi2;
std::string hi3;
std::getline(std::cin, hi3);
std::cout << hi3;
}
마치며, C++을 하면서 이번 글에서는
using namespace std;
없이 예제를 만들어보았는데, 아무리 생각해도 이런 기초적인 작업을 하는데, 이를 사용하지 않고 작업하는 사람들은 겉멋이 든 사람들이 아닐까 싶을 정도로 나한테는 불편한 것 같다.
관련 문제 풀이
오늘 배운 것으로 가장 쉬운 문제를 해결할 수 있다.
2557번: Hello World (acmicpc.net)
1. 화면에 Hello World를 출력해보세요.
#include <iostream>
int main() {
std::cout << "Hello World";
}
2. 문자열을 입력받으면 각각의 문자를 n번 반복해 출력하세요.
#include <iostream>
#include <cstring>
using namespace std;
int main() {
string str;
int num;
int t; cin >> t;
while (t--) {
string answer = "";
cin >>num >> str;
for (int i = 0; i < str.length(); i++) {
for (int j = 0; j < num; j++) {
answer += str[i];
}
}
cout << answer << endl;
}
}
간단하게 만들면 이렇게 만들 수 있습니다.
참고 문헌
Scott Douglas Meyers(2015). Effective C++. Protec Media(프로텍 미디어)
Robert C. Martin(2021).UML 실전에서는 이것만 쓴다(UML for Java Programmers). 인사이트
황기태(2021). 명품 C++ Programming. (주)생능출판사
'ㅇ 공부#언어 > (C++)기초' 카테고리의 다른 글
(기초 C++) 6장. C++에서의 함수 중복과 static 멤버 (0) | 2023.02.26 |
---|---|
(기초 C++) 5장. C++에서의 함수의 참조와 복사 생성자 (0) | 2023.02.26 |
(기초 C++) 4장. C++에서의 포인터 및 동적 생성 (string 클래스 활용) (0) | 2023.02.26 |
(기초 C++) 3장. C++에서 클래스 사용법 (0) | 2023.02.25 |
(기초 C++) 1장. C++의 궁극적 목표와 객체지향 설계 (0) | 2023.02.25 |