학생과 선생의 공통점 = " 사람" 이라는 것

→ 그래서 공통된 사람의 "속성"을 상속받도록 하는 것

상속을 받은 base클래스의 멤버변수는 base의 메서드를 통해 관리를 해줘야한다.

→ 생성자생성에서 derived 클래스에서 base의 멤버변수는 base의 생성자를 호출해야 하는것

private 는 클래스 외부에서 접근을 못한다.

→ 상속에서도 적용이다. 자식클래스 또한 접근이 불가능하다. 하지만 protected는 자식에서는 가능하다. 혹은 base클래스의 멤버변수를 public으로 해서 상속과 클래스 외부에서 사용이 가능하도록 할 수도 있다.

하지만 캡슐화를 권장하기에 private를 사용하는 것을 추천한다.

예제 실습


Base

  1. 언뜻 보면 Base는 string을 다루는 클래스라고 생각하면 된다. 그 외의 string을 받아 새로운 이름으로 덮어씌우는 setName 메서드와 현재 이름을 반환하는 getName 메서드를 통해 데이터를 관리하는 클래스이다.

그렇기에 기본적으로 다른 클래스에 상속하기 적합한 형태로 구성되어 있어 Derived의 학생과 선생의 클래스의 속성 중 하나인 이름에 상속을 부여해서 코드를 효율적으로 다룰 수 있게 된다.

#pragma once
#include <string>
#include <iostream>

class Person {
private:
    std::string m_name;

public:
    Person(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() const { return m_name; }

    void doNothing() const {
        std::cout << m_name << " is doing nothing" << std::endl;
    }
};

Derived

  1. Derived 클래스에서의 "학생" 과 "선생" 은 공통적인 성질 [이름] 을 가지고 있다. 그래서
    이름을 다루는 메서드 [이름 새로 바꾸기] , [이름 반환받기] 또한 [사람] 클래스에서 몰아 넣어서 관리를 하기 쉽도록 할 수 클래스 내부에 메서드를 설정하게 되면 클래스를 수정하기도 그리고 다루기도 쉬워진다.
  2. Derived 클래스에서는 학생은 공부를 선생은 가르침을 하기 때문에 base가 되는 Person과는 다른 Derived 클래스 만의 행동을 추상화하여 생성할 수 있다.
    학생은 멤버변수인 "지능" 과 그리고 "공부 메서드" 를 가지고
    선생은 멤버변수는 없고 "가르침 메서드"를 가지고 있다.

결론적으로는 Base는 상속받는 것들 중에서 공통된 것을 부여받고 공통된 것을 다루는 메서드를 다루게 된다. Derived는 Dervied만의 속성을 다루기만 하면된다. 그로 인해 계속 상속을 해도 각자 담당하는 부분을 담당하는 속성을 나타내는 클래스만으로 접근하기에 수정 또한 담당 클래스를 조금 수정하면 유지 보수가 편하다.

Student Class

#pragma once

#include <string>
#include "Person.h"

class Student : public Person {
private:
    int m_intel;

public:
    Student(const std::string& name_in = "No Name",const int & intel_in = 0)
        : Person{ name_in }, m_intel(intel_in){}

    void setIntel(const int& intel_in) {
        m_intel = intel_in;
    }

    int getIntel() { return m_intel; }
    void studing() {
        std::cout << getName() << "is studing" << std::endl;
    }
    friend std::ostream & operator << (std::ostream& out, const Student& student) {
        out << student.getName() << " " << student.m_intel;
        return out;
    }

};

Teacher Class

#pragma once
#include "Person.h"

class Teacher :public Person{
private:
public:
    Teacher(const std::string& name_in = "No Name")
        : Person(name_in) {

    }

    void teaching() {
        std::cout << getName() << "is teaching" << std::endl;
    }

    friend std::ostream & operator << (std::ostream& out, const Teacher& teacher) {
        out << teacher.getName();
        return out;
    }
};

'프로그래밍 언어 > C++' 카테고리의 다른 글

[따라 배우는 C++] 11.1 상속의 기본(1)  (0) 2020.10.22

상속(Inheritance)란?


클래스에서 상속을 쓰는 이유는 "프로그램 코드의 재사용" 을 목적으로 한다.

직업을 표현하는 객체를 생성한다고 가정하자. 직업이 다양하기에 "판사" , "프로그래머" , "교사" 등 하루 종일 나열할 수 있을 정도로 직업을 무수히 많다.

이런 직업을 표현할 수 있는 객체를 만들 때 직업은 사람이 가지는 직무를 의미하기에 사람의 특징인 "키" , "성별", "몸무게", "나이"공통된 속성이 있다. 이런 공통된 것을 "Person" 클래스로 만들고 "job" 의 클래스에 상속을 하여 코드를 재사용해 직업 마다 모든 걸 매순간 타이핑 하지 않고 상속을 통해 시간을 단축하고 효율적인 작업을 하기 위함으로 사용 된다.

 

 

상속 방법 C++


상속을 받는 클래스 이름을 derived , 상속을 하는 클래스 이름을 Mother 이라고 칭하겠다.

이럴 경우 C++에서는 아래와 같이 표현으로 선언할 수 있다.

// 형태 : Class derived : 접근지정자(public,private,protected) Mother

// ex)
Class Teacher : public Person{
    ...
};

만일 같은 이름의 멤버함수가 있을때는 어떨까?

#include <iostream>
using namespace std;

class Person {
    int age;
public:
    void foo() {
        cout << "Person" << endl;
    }
};

class Teacher : public Person {
    int salary;
public:
    void foo() {
        cout << "job" << endl;
    }
};

int main() {
    Teacher t;
    Person p;

    p.foo(); // Person이 출력될 것이다.
    t.foo(); // Person? job?


    return 0;
}

위의 코드에서 t.foo()는 분명 Person이 출력될것이다. 하지만 p.foo()는 Person을 상속받았고 상속받은 객체는 상속의 멤버함수를 사용할 수 있다. public 일 경우에는 그렇다면 이럴 경우에는 Person이 출력되는지 job이 출력되는지 헷갈릴 수 있다.

  • 이와 같은 경우에는 항상 객체를 우선적으로 실행하게 된다. 무슨 말이냐면 p는 Teacher 객체이다. 그러므로 Teacher의 foo 함수가 실행될 것이다. 그리고 t는 Teacher의 객체이므로 Teacher의 foo 가 실행되게 된다.
  • 만일 Teacher::foo 에서 Person::foo 를 실행시키고 싶다면 범위확인연산자( :: ) 를 사용하면 된다. → Person::foo()

 

 

상속 살펴보기


상속을 받았는데 상속한 클래스에 접근 하고 싶을 때에 방법이 있다.

  1. 상속 객체의 멤버변수를 public으로 바꾸는 방법

  2. 멤버 변수가 private 로 선언 된 클래스에 접근하기 위해서는 상속해준 클래스의 멤버 함수를 이용한다. 추천 

     #include <iostream>
     using namespace std;
    
     class Person {
         int m_age;
     public:
         void setAge(int age) {
             m_age = age;
         }
         void Show() { cout << "age " << m_age << endl; }
     };
    
     class Teacher : public Person {
         int m_salary;
     public:
         void setD(int sal)
         {
             m_salary = sal;
         }
         void setAge(int age)
         {
             Person::setAge(age); // Person의 멤버함수를 호출한다.
         }
    
         void Show() {
             Person::Show();
         }
     };
    
     int main() {
         Teacher t;
    
         t.setAge(10);
         t.Show();
    
        return 0;
    }
    

'프로그래밍 언어 > C++' 카테고리의 다른 글

[따라배우는 C++] 상속의 기본(2)  (0) 2020.10.29

<정답 코드>

C++

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

int main() {
    int T;
    cin >> T;
    getchar();
    for (int i = 0; i < T; i++) {
        int sum{ 0 };
        string text;
        getline(cin, text);
        string numstr;

        for (int c = 0; c < text.size(); c++) {
            if (text[c] != ' ') {
                numstr.push_back(text[c]);
            }
            else {
                sum += stoi(numstr);
                numstr.clear();
            }
        }
        sum += stoi(numstr);
        cout << sum << endl;
    }

    return 0;
}

Python

n = int(input())

for i in range(n):
    arr = map(int,input().split(' '))
    sum = 0
    for i in arr:
        sum+=i

    print(sum)

<문제 해결 전략>

이 문제에서 까다로운 것은 입력이 주어지는 데 그 갯수가 주어지지가 않는다. 속성으로 배운 파이썬에서는 한줄로 입력받고 바로 map 메서드를 통해 int로 바꿀 수 있는 반면 c++에서는 문자열로 한줄을 받고 문자열을 나눠주고 stoi 메서드를 통해 int로 바꿔줘야 해서 번거롭다

또한 c++에서는 getline(cin,text) 부분에서 앞서 T를 입력받을 때 "줄바꿈 문자\n "가 들어가서 바로 입력이 받아지므로 getchar()를 하는 것을 잊으면 안된다!

<TIL>

파이썬.. 정말 좋긴 하다.

비전공으로 카카오 1차 코딩테스트를 통과하고 좋아라 했습니다. 1년 동안 알고리즘과 자료구조 ,C++ 프로그래밍 언어 기본만 주구장창 파니 이제 알고리즘은 어느정도 통과가 많이 되지만..

역시 걱정했던 CS 전공지식과 기본기가 중요한 것 같습니다. 

비전공이기에 나름 노력 해봤지만 전공지식 운영체제, 네트워크, DB는 어떻게 방향을 잡아야할지 모르겠습니다. 필기테스트에서 시간복잡도,자료구조 문제는 쉽게 풀리는데 가장 접하기도 힘들었고 제대로 공부하고 있는지 매번 고민하고 방황하던 CS전공지식이 발목을 잡네요... 아쉽지만 더 노력해야겠습니다. 개인적으로 전공자 분들에게는 "정처기" 가 다 따는 것이라 낮게 보시는 것 같은데 비전공자인 저한테는 나름 비전공생이지만 학습했다고 증명할 수 있는 하나의 도구라 생각해서 이번년도 안에 내년도를 위한 정처기 책이 나온다면 바로 구매해서 공부할 예정입니다.

그리고 시험으로 넘어와서 카카오 2차에서 낯선환경과 낯선문제에 대해 적응이 부족하단 걸 크게 깨달았습니다. 앞으로는 C++ 뿐만 아니라 Python 그리고 JS를 한번 배워볼까 합니다. 무기가 많으면 좋다고 느껴서..ㅠ C++는 STL하고 OOP관련해서 집중적으로 깊게 팔 예정입니다. 어느 정도 시간이 있다면 C++17 C++20을 한번 경험해보고 싶기도 합니다 ㅎㅎ

또한 프로젝트 경험이 정말 필요하다고 느낀 시험이었습니다.(REST API, JSON을 처음 써봤어요ㅠ) 정적인 데이터로 효율적으로 답을 내는게 1차 코딩테스트라면 2차에서 제가 느낀 것은 동적인 데이터를 기반으로 자신이 정한 기준으로 어떻게 효율적으로 짤 것인가? 가 중점이라고 생각합니다. 1차는 완벽한 정답을, 2차에서는 어떻게 계속 코드를 발전시키는 가를 보는 것 같습니다. 물론 아직 부족하기에 카카오의 큰 뜻은 알지 못하겠지만. 정말!! 감사하고 소중한 경험이었습니다.

 

 

 

[PS]최종적으로 제게는 교육이 필요한 것 같습니다. 이번에 싸피를 뽑을 예정인 것 같은데.. 알고리즘을 1학기에 배우고 2학기에는 프로젝트를 중점적으로 한다고 하는데..

무척 가고 싶지만 워낙 경쟁률이 높아서 확실치는 않지만 최선을 다하겠습니다.

제가 부족한 부분이 알고리즘에서도 구현은 자신 있으나 웰 논 알고리즘을 잘 알지 못하다고 생각합니다. 다익스트라나 BFS,DFS 이런것들처럼 기법으로 문제가 쉽게 풀리는데 그러한 부분에서 불안정한 문제해결역량을 느꼈습니다. 아마 싸피를 하면 그런 역량에서 기반이 튼튼해질 것 같습니다. 또한 비전공이지만 개발자를 꿈꾸는 저같은 사람과의 인적네트워크, 다양한 프로젝트를 경험할 수 있을 것이라 기대합니다. 싸피에서는 1학기에는 배운 것을 관통해서 하나를 만들고 2학기에는 하루종일 프로젝트 개발은 한다고 하니 좀 더 다양한 시각을 쌓을 수 있을 것이라 기대됩니다. 

나이 제한이 딱 커트라인인데.. 제발 붙었으면..!!

분산처리

RANK of solved.ac: B3
Tags: #구현, #수학
문제 링크: https://www.acmicpc.net/problem/1009
문제 번호: 1009

<정답 코드>

#include <iostream>
using namespace std;

int main() {
    int T;
    cin >> T;

    for (int tc = 0; tc < T; tc++) {
        int a, b;
        scanf("%d %d", &a, &b);
        int digit_one_num=1;
        while (b--) {
            digit_one_num = (digit_one_num*a) % 10;
        }
        cout << (digit_one_num == 0 ? 10 : digit_one_num) << endl;
    }

    return 0;
}

<문제 해결 전략>

  • 1의 자리만 보면 된다. 2^9 =512 에서 510등까지는 1~10컴퓨터를 51번 채운거다. 그러므로 남는 2가 실제로 512번이 앉는 컴퓨터 자리이다.
  • 10번과 같은 경우 나머지가 0이 되는데 이럴 경우에만 출력을 10으로 해주면 된다.

 

 

14442번: 벽 부수고 이동하기 2

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000), K(1 ≤ K ≤ 10)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.

www.acmicpc.net

#문제접근

2차원 배열의 변수명 stepandblock[y][x] 는 y와 x 에 도달하기 까지 최단 거리와 부순 벽의 갯수를 저장합니다. 그래서 stepandblock에 저장된 거리와 벽의 갯수와 비교를 해가며 적어도 하나의 변화점이 생길경우 예를 들어 저장된 최단거리보다 더 짧은 거리일 경우 혹은 부순 벽의 갯수가 훨씬 적은 경우 bfs에 push를 해주고 새로 갱신해줍니다. 그렇게 구현한 뒤 bfs를 구현하게 되면 stepandblock[y][x]는 {y,x} 좌표에 도달할때 최단거리 그리고 벽의 갯수가 저장되게 되는데 bfs가 완료하게 되면 y x에는 부순 벽의 갯수가 아닌 최단 거리를 기준으로 데이터가 갱신이 완료됩니다.

그 후 while문 밖에서 기존의 초기화에서 INT_MAX값일 경우 -1을 출력하게 되고 INT_MAX값이 아니라면 저장된 최단거리를 출력했습니다.

 

#정답코드

 

#include <iostream>
#include <vector>
#include <string>
#include <deque>
#include <climits>
#include <algorithm>
using namespace std;

const int dx[] = { 1,-1,0,0 };
const int dy[] = { 0,0,1,-1 };

struct info {
	std::pair<int, int> pos;
	int step;
	int block_cnt;
	info(const std::pair<int, int> pos, int step, int block_cnt) :pos(pos), step(step), block_cnt(block_cnt)
	{}
};



int main() {

	int N, M, K;
	cin >> N >> M >> K;
	std::vector<std::string> arr(N);
	for (auto& ele : arr)
		cin >> ele;

	std::deque<info> bfs;
	bfs.push_back(info({ 0,0 }, 0, 0));
	std::vector<std::vector<std::pair<int, int> > > stepandblock(N, std::vector<std::pair<int, int> >(M, { INT_MAX,INT_MAX }));//first는 step , second는 block갯수로 하자


	stepandblock[0][0].first = 0;
	stepandblock[0][0].second = 0;

	while (!bfs.empty()) {
		auto p = bfs.front();
		bfs.pop_front();

		//최단경로이니까 우선 최단거리일때 같은 경우에는 더 부술수 있는 것이 좋겠지

		for (int i = 0; i < 4; i++) {
			int py = p.pos.first + dy[i];
			int px = p.pos.second + dx[i];
			int pstep = p.step + 1;
			if (0 <= py && py < N && 0 <= px && px < M) {//범위 안에 있을 경우
				int pblock = p.block_cnt + arr[py][px] - '0';

				if (pblock <= K && ((pblock < stepandblock[py][px].second) + (stepandblock[py][px].first > pstep))>=1 ) {
					bfs.push_back(info({ py,px }, pstep, pblock));
					stepandblock[py][px].first = min(stepandblock[py][px].first,pstep);
					stepandblock[py][px].second = min(stepandblock[py][px].second,pblock);
				}

			}

		}

	}


	if (stepandblock.back().back().first != INT_MAX && stepandblock.back().back().second != INT_MAX)
		cout << stepandblock.back().back().first + 1 << endl;
	else
		cout << -1 << endl;


	return 0;
}

 

+ Recent posts