728x90

1. 힙 자료구조

0. 개념

- max heap, min heap ((a)트리 형태의 자료구조로 설명하지만, 실제로는  (b)1차원 배열 형태로 표현)

2009 Introduction to Algorithms Third Ed.

- 인덱스는 위치에 따라 고정되어 있는 느낌,,

왼쪽 자식의 인덱스 = (부모의 인덱스) * 2
오른쪽 자식의 인덱스 = (부모의 인덱스) * 2 + 1
부모의 인덱스 = (자식의 인덱스) / 2
https://gmlwjd9405.github.io/2018/05/10/data-structure-heap.html

 

- max heap에서, 부모가 자식보다 크거가 같은 것은 보장되지만, 자식 간 대소비교는 인덱스로 구분하기 어려움. 

https://gmlwjd9405.github.io/2018/05/10/data-structure-heap.html

 

2. 주요 쓰임 두 가지:

(1) 힙 정렬 (2) 우선순위 큐

 

 

3. Building heap

3-1. 원소 삽입 push : 마지막 노드에 삽입 

힙 성질 만족할 때까지 부모 노드와 swap (아래→위의 Bottom Up 방식)

→ 반복 반복...

 

3-2. 원소 삭제 pop : max heap에서 원소를 삭제한다는 것은 root node(=최댓값)을 삭제한다는 것 

→ 최댓값을 미리 저장 후,

→ 삭제된 자리(root)에 마지막 노드 A를 가지고 옴 (=마지막 노드와 루트 노드를 swap)

힙 성질 만족할 때까지(=A보다 더 큰 자식노드가 없을 때까지) A를 A의 더 큰 자식노드와 swap 반복...

    : 위→아래의 Top Down 방식

→ 미리 저장해둔 최댓값을 return시키고, heap의 크기를 1 감소시킴

 

 


2. 힙 정렬

1-1. 개념

max heap(내림차순)이나 min heap(오름차순) 자료구조를 활용하여 sorting하는 방법

 

1-2. 강점

- 시간 복잡도가 좋은 편

- 힙 정렬이 가장 유용한 경우는, 전체 자료를 정렬하는 것이 아니라, 가장 큰 값 몇 개만 필요할 때.

 

1-3. 방법

- 힙은 1차원 배열로 구현됨. 정렬해야 할 n개의 input들을 최대 힙 삽입을 통해 차례대로 삽입함.

(=즉 우리의 input으로 구성된 힙 자료구조를 직접 생성)

- 최대 힙으로 구성된 1차원 배열에서, 차례대로 삭제함 (=root에 있는 최댓값이 나옴)

- 그때마다 최대 힙 트리는 update됨 (힙의 성질 만족)

 

1-2. 복잡도

- 전체 t-c는 O(nlgn)

- Worst t-c는 omega(nlgn)

- 원소가 중복이 없을 때는 Best t-c가 omega(nlgn)


힙, 힙정렬 개념 야무지게 잘 정리된 페이지 링크 모음 🤩

 

https://gmlwjd9405.github.io/2018/05/10/data-structure-heap.html

 

[자료구조] 힙(heap)이란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

https://gmlwjd9405.github.io/2018/05/10/algorithm-heap-sort.html

 

[알고리즘] 힙 정렬(heap sort)이란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

https://www.daleseo.com/python-heapq/

 

파이썬의 heapq 모듈로 힙 자료구조 사용하기

Engineering Blog by Dale Seo

www.daleseo.com

https://docs.python.org/ko/3/library/heapq.html

 

heapq — Heap queue algorithm

Source code: Lib/heapq.py This module provides an implementation of the heap queue algorithm, also known as the priority queue algorithm. Heaps are binary trees for which every parent node has a va...

docs.python.org

https://velog.io/@junhok82/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%ED%9E%99heap

 

[자료구조] 힙(heap)

이진 힙(binary heap)은 우선순위 큐(priority queue)를 위한 자료구조다. 그런데 왜 우선순위 큐는 기존에 있는 큐와 같은 방식을 이용하지않고 heap이라는 자료구조를 이용하는 것일까? 그에 대한 답은

velog.io

 

728x90

728x90

Intent

intent: 우편배달부. 의사소통을 책임짐

  • 액티비티와 액티비티 간
  • 앱과 앱 간

 

타입 두 가지

1) 명시적 Intent

- 하나의 앱 내에서 액티비티와 액티비티 간 소통 시 자주.

- 보낸 이와 받는 이가 명시되어 있음

 

Intent intent = new Intent(this, NewActivity.class);

startActivity(intent);

 

보낸 이 : this(현재의 액티비티)

받는 이: NewActivity.class

 


2) 암시적 Intent

- 앱과 앱 간(다른 앱의 활동을 호출하여 원하는 기능을 수행, 웹 브라우저를 열어 특정 페이지를 표시하거나, 연락처 앱을 열어 특정 연락처를 표시하는 등)

- 시스템 서비스 사용: Android 시스템의 여러 서비스를 활용( 이미 안드로이드에 내장되어 있는 기능) 예를 들어, 카메라 앱을 시작하여 사진을 찍는 기능, 위치 서비스를 사용하여 현재 위치를 얻는 기능

- 받는 사람과 보내는 사람이 명시되어있지 않음

 

sendIntent.setAction(Intent.ACTION_CALL);
startActivity(sendIntent);
Intent sendIntent = new Intent();

 


Intent 없는 상태

...

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

	@Override
    protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState); //onCreate는 AppCompatActivity 클래스에 정의된 콜백메서드
    setContentView(R.layout.activity_main);
    
    Button button = (Button) findViewById(R.id.btn_call); //Button은 view에 속한 컴퍼넌트
    button.setOnClickListener(this); //this는 OnClickListener 인터페이스
    
    }
    
    @Override
    publid void onClick(View view) {
    	Toast.makeText(MainActivity.this, "Click!!", Toast.LENGTH_SHORT).show();
        } //여기서 this는 입력받은 매개변수인 view, 즉 클릭된 view의 컴퍼넌트인 button
        //여기서 onClick은 OnClickListener 인터페이스 내부에 정의된 콜백 메서드
        //즉, button이 클릭되면 '클릭되었다'는 것을 OnClickListener가 알아차리고 이에 따라 onClick 콜백 메서드가 실행됨
    }

 

암시적 Intent

...

@Override
public void onClick(View view){

    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_CALL);
    startActivity(intent);
    }
}

 

명시적 Intent

...

@Override
public void onClick(View view) {
    Intent intent = new Intent(MainActivity.this, CallActivity.class); //또다른 자바 클래스 activity를 생성함
    startActivity(intent);
    }
}

 

728x90
728x90

0) 안드로이드의 삼대장&원수 (??)

출처: https://www.youtube.com/watch?v=49N59HnCAxQ&t=109s 

- 원수: Activity !!! : foreground(눈에 보일 때만) 일을 하는 녀석
   액티비티는 곧 화면 (UI를 보여주고 실제 기능까지 한다. 다 한다.)

- 대장 1: ContentProvider: 자료나 데이터 받아오는 경우 (사용하지 않는 경우 있음)

- 대장 2: Service: background(눈에 보이지 않는데) 일을 하는 녀석

- 대장 3: BroadcastReceiver: 알림을 도와주는 녀석 (ex. 카톡 메시지가 왔을 때 '메시지 왔다'는 사실을 알려주는 것.) 콜백과 비슷한 기능.. 통신 느낌.

https://www.youtube.com/watch?v=49N59HnCAxQ&t=109s

1) Activity의 활동 수명

https://developer.android.com/guide/components/activities/activity-lifecycle?hl=ko


2) View: 화면 그 자체

  • Activity에 씌우는 화면 껍데기
  • XML, Java 둘 중 하나로 작성 가능 (보통 XML)
    • xml파일에 <TextView.../> 하는 게 다 여기에 해당
  • 보통 widget, adapter, layout 계열로 나눌 수 있음
    • widget; TextView, ImageView 등. 용도가 뚜렷함.
    • adapter; ListView, GirdView, RecyclerView 등. 여러 개의 많은 정보를 길게 스크롤하여 나열할 때 많이 씀

3) Layout

  • layout; LinerLayout, RelativeLayout, FrameLayout... 화면 공간 배분할 때 많이 쓰임.

4-1) Thread

- 작업의 흐름

- 기본적으로 main / UI thread가 존재함

4-2) Multi threading : 분업

출처: https://www.youtube.com/watch?v=7oeSMTfZ2mo&t=1129s 

https://www.youtube.com/watch?v=7oeSMTfZ2mo&t=1129s

- 단!! 무조건 많을수록 좋은 것은 아니다: 빠른 속도로 다양한 일을 하기에, 동시에 되는 것처럼 착각하는 경향이 있음.

- 일반적인 앱의 경우, main에 1~2개 Thread만 멀티로 두는 편

https://www.youtube.com/watch?v=7oeSMTfZ2mo&t=1129s


https://www.youtube.com/watch?v=7oeSMTfZ2mo&t=1129s

- Thread: java에서 제공하는 클래스

- Handler: android에서 제공하는 클래스

 

방법 1: 자바스러움

1) Thread가 실제 계산/어떤 일을 수행하고 나서. 일을 다 한 내역을 Handler thread에 보내줌

2) Thread로부터 받아온 일 결과물을, Handler를 통해 간접적으로 반영해줌

 

방법 2: AsyncTask

- Android Recommended

- 간단하게 새로운 쓰레드를 생성해서 작업할 수 있음 (코드도 간결)

 

 


https://www.youtube.com/watch?v=LvBNVuXbS3E 

 

728x90
728x90

인터페이스의 쓰임새

*UI(유저 인터페이스) 아님!!!

  • 다중 상속
  • 콜백 메소드

인터페이스의 기능: 1) 다중 상속

1. Java에서는 2개 이상의 상속이 불가능하다

2. '상속(extends)' 대신 '구현(implements)'하자.

3. by '인터페이스'

 

상속 (extends) 구현 (implements)
- 아이덴티티를 보유한다
ex) 개는 동물이다 (개는 동물에 완전히 속하므로)
- 역할(role)을 부여한다
ex) 개는 반려동물이다 (일부 개에게만 해당)

- 구현 implements은 변수를 상속받지 않는다 (오로지 행동 메서드만 취함)

 

 attackable이라는 interface를 만들면 우리가 지정한 대상에 한해서 attack이라는 메소드를 공유할 수 있도록 함

(부모클래스에 attack 포함하면 그것을 상속하는 모든 클래스가 attack할 수 있게 되므로 No)

 

https://www.youtube.com/watch?v=49COMLtdY04

→ sell 파는 것 & upgrade : Trade와 관련된 것들은 서로 공유할 수 있도록 함.

 


인터페이스의 기능: 2) 콜백 함수

Callback

사용자가 버튼을 눌렀을 때(event) 뭔가 하고싶어

- 앱을 사용하다가 홈버튼을 누르면 어떻게 처리하지?

- 다운로드가 완료되었으면 알림을 울릴 수 없을까?

 

콜백 메소드: 이러한 시점(event)에 호출되는 메소드

Q. 어떤 게 콜백이지?

- 콜백 메소드는 보통 onClick, onTouch, onPressed 등 on~이 붙는다.

- 콜백을 정의한 인터페이스는 보통 OnClickListener, OnTouchListener 등 Listener가 붙는다.

https://www.youtube.com/watch?v=IBxiy7dzv_4&t=333s

 

- OnDownloadListener: 인터페이스

- Download(this)의 this는 Downloader 클래스일 수도 있고, OnDownloadListener 인터페이스일 수도 있는데, 실제 Download 함수 정의한 내용에서 매개변수로 오직 OnDownloadListener만을 취하므로, 후자를 가리키게 됨

- Download 함수에서 정의한 코드가 완료되면 listener 인터페이스에 onDownloadFinish()라는 메소드가 실행됨.

- "다운로드라는 이벤트를 완료했어"라는 알림을 onDownloadFinish라는 콜백함수가 listener 인터페이스에게 전달해주는 것임.

- onDownloadFinish 콜백 함수는, 실제로 OnDownloadListener이라는 인터페이스로부터 받아온 (@Override) 함수임.

 



reference: 겜팔이의 안드로이드 세뇌교실

728x90

728x90

이벤트 내용

 

- Count 버튼을 누르면 수를 카운트 하고

- 카운트 한 만큼 화면에 띄우기

- Reset 버튼을 누르면 카운트 값 리셋하기


MainActivity.java

package com.example.cute_tutorial;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private int count = 0;
    private TextView countText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        countText = (TextView) findViewById(R.id.count_text);
        countText.setText("0");
    }

    public void buttonCount(View view) {
        count++;
        if (countText != null) {
            countText.setText(Integer.toString(count));
        }
    }

    public void buttonReset(View view) {
        count = 0;
        if (countText != null) {
            countText.setText(Integer.toString(count));
        }
    }
}

 

private int count = 0;
private TextView countText;

 

Android 개발에서 TextView는 사용자 인터페이스(UI)를 구성하는 데 사용되는 위젯(Widget) 중 하나

- 주요 기능: 텍스트를 화면에 표시 (정적/동적)

 

- 레이아웃 파일(XML) 또는 Java 코드에서 사용됨

(1) XML에서 TextView 위젯 추가

<TextView
    android:id="@+id/myTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello, World!"
    android:textSize="18sp"
    android:textColor="#000000"
    android:gravity="center"
    android:layout_gravity="center"/>

 

(2) Java 코드에서 TextView를 조작하려면, findViewById() 메서드를 사용하여 xml에 정의된 TextView의 id값을 참조하는 방식으로 해당 TextView 객체를 가져오면 됨

- 객체를 가져오기만 하면, 나머지 이벤트는 기본 프로그래밍 방식으로 처리.

 

countText = (TextView) findViewById(R.id.count_text);
countText.setText("0");

 

- 안드로이드 앱 내 xml 파일에서 'count_text'라는 Id를 가진 TextView를 찾고

- 해당 TextView에 "0"이라는 텍스트를 보이게 하는 코드

 

findViewById(R.id.count_text)에서의 R은 안드로이드 앱의 리소스(Resources)를 나타내는 클래스

R 클래스는 앱이 컴파일될 때 자동으로 생성되며, 리소스의 유형과 이름에 따라 여러 하위 클래스를 가짐

- R.layout는 레이아웃 리소스에 대한 상수를 포함하는 클래스

- R.id 레이아웃 내의 뷰에 할당된 고유한 ID 관리

 

    public void buttonCount(View view) {
        count++;
        if (countText != null) {
            countText.setText(Integer.toString(count));
        }
    }

 

아까 id 로 객체 지정한 countText를 바꾸어주는 함수 설정

해당 함수는 xml 파일에서 정의된 위젯들 중에, buttonCount라는 이벤트와 연결되어 있는 버튼이 눌렸을 때 동작함

 


activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_marginStart="137dp"
        android:layout_marginTop="246dp"
        android:text="Hello World!" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_marginStart="62dp"
        android:layout_marginTop="66dp"
        android:text="Name" />

    <Button
        android:id="@+id/buttonCount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginStart="158dp"
        android:layout_marginTop="316dp"
        android:text="Count!"

        android:onClick="buttonCount"/>

    <Button
        android:id="@+id/buttonReset"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="291dp"
        android:text="Reset!"

        android:onClick="buttonReset"
        />

    <TextView
        android:id="@+id/count_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="210dp"
        android:text="TextView" />

</RelativeLayout>

 

728x90
728x90

1. 동적결합(Dynamic Binding)의 개념

프로그램이 실행 중일 , 어떤 함수나 메서드를 호출할 실제로 어떤 코드를 실행할지를 결정하는 것

- 즉, 함수 호출이 어떤 객체나 클래스의 실제 버전을 호출할지 런타임(runtime) 시점에 결정하는 

- 주로 객체 지향 프로그래밍에서 다형성을 구현하는 사용됨

 

1) '프로그램 실행 중'에 객체의 실제 타입을 고려

2) 해당 타입에 맞는 함수나 메서드를 호출

 

- 이를 통해 서로 다른 객체 동일한 함수 또는 메서드 호출하더라도, 객체의 고유한 동작 수행할 있음


2) c++에서 동적 결합을 구현하는 두 가지 주요 메커니즘

 

2-1. 가상함수 (virtual functions)

- 함수 앞에 virtual 키워드를 사용

- 가상 함수는 기본형 클래스에서 선언되고 파생 클래스(derived class)에서 재정의(override)할 수 있는 함수

- 가상 함수를 사용하면 런타임 시에 객체의 실제 타입에 따라 올바른 함수 버전이 호출됨

class Shape {
public:
    virtual void draw() {
        // 기본 구현 }
};

class Circle : public Shape {
public:
    void draw() override {}
};

2-2. 가상테이블 (virtual table)

- 가상 함수를 사용할 때, C++ 컴파일러는 객체에 대한 가상 함수 포인터 테이블을 생성함

- 테이블은 가상 함수의 주소를 저장하고, 실제 함수 호출 시에 테이블을 참조하여 올바른 함수를 호출함

 

void drawShape(Shape* shape) {
    shape->draw(); // 동적 결합
}

int main() {
    Circle circle;
    Square square;

    drawShape(&circle); // Circle 클래스의 draw()가 호출됨
    drawShape(&square); // Square 클래스의 draw()가 호출됨

    return 0;
}

구체적인 예제로 동적 결합 이해하기

 

기초형 클래스의 pointer으로 구성된 포인터 array를 선언

→ 해당 array에 기초형 클래스 Time뿐 아니라, 상속 클래스인 NewTime의 주소값도 저장됨

array의 각 원소에 대해 virtual 메서드인 show()를 실행시켜줌

(show 실행될 때마다, 어떤 class 타입인지 실시간으로 판단해스 해당 타입에 대응되는 virtual 메서드를 실행시킴)

 

time.h

#include<iostream>
using namespace std;

#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H

class Time{
private:
    int hours;
    int mins;
public:
    Time();
    Time(int, int);

    /* virtual 통해 가상 메소드 선언 */
    virtual void show(); //가상메소드
    virtual ~Time(); //파괴자 역시 가상 메소드로 선언

    int getHour(){return hours;}
    int getMins(){return mins;}

    Time operator*(int n);
    friend Time operator*(int, Time&);
};

class NewTime : public Time {
private:
    int day;
public:
    NewTime(); //생성자
    NewTime(int, int, int); //생성
    void show();
};

#endif //FIRE_C_TIME_H

time_func.cpp

#include "time.h"

Time::Time(){
    hours = 0;
    mins = 0;}

Time::Time(int h, int m){
    hours = h;
    mins = m;}

void Time::show(){
    cout << hours << "시간 " << mins << "분" << endl;}

Time::~Time(){}

NewTime::NewTime() : Time(){
day = 0;
}

NewTime::NewTime(int h, int m, int d) : Time(h, m) {
day = d;
}

void NewTime::show(){
    cout << day << "일 " << getHour() << "시간 " << getMins() << "분" << endl;
}

main.cpp

#include "time.h"
#include "time_func.cpp"

const int MAX = 3;

int main(){
    Time* times[MAX]; //기초형 Time 클래스의 포인터들이 저장된 배열
    //이곳에 Time 기초형 클래스의 포인터도, NewTime 상속 클래스의 포인터도 담김
    int day;
    int hours;
    int mins;

    for (int i = 0; i < MAX; i++) {
        cout << i + 1 << "번째 원소를 정의합니다." << endl;
        cout << "시간을 입력하십시오." << endl;
        cin >> hours;
        cout << "분을 입력하십시오." << endl;
        cin >> mins;
        char check;
        cout << "일 정보가 있다면 1, 없다면 0을 입력하십시오." << endl;
        cin >> check;
        if (check == '0')
            times[i] = new Time(hours, mins);
        else {
            cout << "일을 입력하십시오." << endl;
            cin >> day;
            times[i] = new NewTime(hours, mins, day);
        }
    }

    for (int i = 0; i < MAX; i++){
        cout << i+1 << "번째 정보입니다." <<endl;
        times[i]->show();
        //show를 virtual로 선언했기 때문에,
        //times: time의 pointer 배열이지만
        //Times이면 Time의 show()가, NewTime이면 NewTime의 show()가 실행됨
    }

    for (int i = 0; i < MAX; i++){
        delete times[i]; //delete의 경우 time형에 대한 delete만 이루어짐
        //NewTime 객체의 경우 제대로 delete되지 않음
        //이를 위해 파괴자 역시 virtual로 선언해야 함

    }

    return 0;}
728x90
728x90

1. 기초 클래스에서 가상 메서드를 선언하면, 그 함수는 기초 클래스 및 파생되는 클래스에서 모두 가상이 됨

2. 객체에 대한 참조 or 포인터를 사용하여, 가상 메서드가 호출되면 → 참조나 포인터를 위해 정의된 메서드를 사용하지 않고 객체형을 위해 정의된 메서드를 사용한다. (=동적 결합)

3. 상속을 위해 기초 클래스로 사용할 클래스를 정의할 때, 파생 클래스에서 다시 정의해야 되는 클래스 메서드들은 가상 함수로 선언해야 한다.

 


기초 클래스의 데이터와 상속 클래스의 데이터를 출력하는 함수(메서드)를 만들고자 한다.

기존에는 각각에 서로 다른 메서드 show() / print() 를 정의했었다면,

이번에는 동일한 이름의 show() 메서드로 기초 클래스와 상속 클래스의 데이터를 출력해주고자 한다.

이를 위해서는 기초 클래스의 public 영역에서, virtual 키워드를 통해 show 메서드를 '가상 메서드'로 선언하여야 한다.

 

time.h

#include<iostream>
using namespace std;

#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H

class Time{
private:
    int hours;
    int mins;
public:
    Time();
    Time(int, int);

    /* virtual 통해 가상 메소드 선언 */
    virtual void show();
    //가상 메소드: 프로그램에서 서로 독립된 메소드 정의가 있다는 것을 알려줌
    //show가 호출되었을 때, 호출한 객체를 따져서, 대응되는 함수를 선택함
    //현재 show가 가상 메소드로 정의된 상태

    int getHour(){return hours;}
    int getMins(){return mins;}
    ~Time();

    Time operator*(int n);
    friend Time operator*(int, Time&);
};

class NewTime : public Time {
private:
    int day;
public:
    NewTime(); //생성자
    NewTime(int, int, int); //생성
    void show();
};

#endif //FIRE_C_TIME_H

 

time_func.cpp

#include "time.h"

Time::Time(){
    hours = 0;
    mins = 0;}

Time::Time(int h, int m){
    hours = h;
    mins = m;}

// (1) 기초형 클래스에서 정의된 show() 메서드
void Time::show(){
    cout << hours << "시간 " << mins << "분" << endl;}

Time::~Time(){}

NewTime::NewTime() : Time(){
day = 0;
}

NewTime::NewTime(int h, int m, int d) : Time(h, m) {
day = d;
}

// (2) 상속 클래스에서 정의된 show() 메서드
/* show가 어디에서 호출되느냐에 따라 다른 기능 수행 - Time vs NewTime */

void NewTime::show(){
    //show(); 이름이 동일해서 재귀적으로 호출되는 문제 발생
    //기초형 클래스의 public 함수를 새로 생성 - private 멤버변수를 반환해주는.
    cout << day << "일 " << getHour() << "시간 " << getMins() << "분" << endl;
}

 

main.cpp

#include "time.h"
#include "time_func.cpp"

//public 함수를 다형으로 사용하기

int main(){
    Time temp1(1, 2);
    NewTime temp2(3, 30, 2);

    temp1.show();
    temp2.show();

    return 0;}

/*1시간 2분
2일 3시간 30분*/

 

728x90

'개발 > c++' 카테고리의 다른 글

[c++] 서로 다른 & (참조자/주소반환)  (0) 2023.09.24
[c++] 동적 결합  (0) 2023.09.11
[c++] 클래스 상속  (0) 2023.09.10
[c++] friend (feat. 연산자 오버로딩 응용)  (0) 2023.09.10
[c++] 연산자 오버로딩  (0) 2023.09.10
728x90

- 기초 클래스 (오리지널 원본)

 

- 파생 클래스

1. 파생 클래스형의 객체 안에는 기초 클래스형의 데이터 멤버들이 저장됨

2. 파생 클래스형의 객체는 기초 클래스형의 메서드를 사용할 수 있음

3. 단, 기초 클래스형의 private member에는 접근할 수 없음 → 멤버 초기자 리스트를 통해 접근할 수 있게 됨

4. 파생 클래스는 자기 자신의 생성자를 필요로함

5. 파생 클래스는 부가적인 데이터 멤버들과 멤버 함수를 임의로 추가할 수 있음

 

**아래 주석코드의 설명 잘 읽기,,

 

time.h

#include<iostream>
using namespace std;

#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H

class Time{
private:
    int hours;
    int mins;
public:
    Time();
    Time(int, int);
    void show();
    ~Time();
};

/*클래스 상속*/
//파생 클래스: 오리지널 클래스인 Time을 상속받음
class NewTime : public Time {
private:
    int day;
public:
    NewTime(); //생성자
    NewTime(int, int, int); //생성자
    void print();

};

#endif //FIRE_C_TIME_H

time_func.cpp

#include "time.h"

Time::Time(){
    hours = 0;
    mins = 0;}

Time::Time(int h, int m){
    hours = h;
    mins = m;}

void Time::show(){
    cout << hours << "시간 " << mins << "분" << endl;}

Time::~Time(){}


// " : Time()" 부분은 '멤버 초기자 리스트'
// 기초형 클래스의 private member에 접근할 수 있게 됨
NewTime::NewTime() : Time(){
//Time()이 먼저 생성된 뒤 해당 내용이 NewTime에 전달되어, hours = mins = 0으로 초기화됨
//NewTime()에서는 day만 초기화해주면 됨
day = 0;
}

NewTime::NewTime(int h, int m, int d) : Time(h, m) {
//Time(h,m)이 생성된 뒤 NewTime의 h, m에 전달해줌
//d만 따로 정의해주면 됨
day = d;
}

void NewTime::print(){
    cout << day << "일 " << endl;
    show();
    // hours와 mins는 NewTime의 멤버변수가 아니므로 직접 접근하지는 못함
    // 따라서 기초형 클래스의 함수 통해 출력함
}

main.cpp

#include "time.h"
#include "time_func.cpp"

int main(){
    NewTime temp1();
    NewTime temp2(3, 30, 2);

    temp2.print();

    return 0;}

/*2일
3시간 30분*/
728x90
728x90

1. friend 개념

- 클래스의 멤버 함수는 아니지만, 해당 클래스의 private 멤버에 접근할 수 있도록 하는 도구

- 형태: friend 함수 / friend 클래스 / friend 연산자 오버로딩

** friend 함수는 멤버함수가 아니므로 .이나 -> 통해 호출 불가능

** 그러나 private 멤버변수에 대해, 멤버함수와 동등한 접근 권한을 가짐

 

* 주의

- friend는 비공개 멤버에 대한 접근을 허용하는 기능이므로 남용하지 않는 것이 안전

- 클래스 간의 관계를 명확하게 구성하고, 필요한 경우에만 friend 사용할

 

2. friend를 사용하는 주요 경우

2-1. friend 함수: '함수'를 클래스의 freind로 선언

해당 함수는 클래스의 멤버 함수가 아니지만 클래스의 private 멤버에 접근할 수 있게 됨

class MyClass {
private:
    int privateData;

public:
    MyClass(int data) : privateData(data) {}
    friend void friendFunction(MyClass obj); // 'friend 함수' 선언};

→ friendFunction 함수는 MyClass 클래스 '외부'에서 정의되어 있음

외부에서 정의된 함수가 MyClass의 멤버 변수에 접근하려면, MyClass 클래스 내부에 그것의 원형이 선언되어 있어야 함

→ 더 원하는 친구가 직접 발품 팔기.~! ㅎㅎ

 

 

2-2. friend 클래스: '클래스'를 다른 클래스의 friend로 선언

다른 클래스의 private 멤버에 접근할 수 있게 됨

class FriendClass {
private:
    int secretData;
public:
    FriendClass(int data) : secretData(data) {}};


class MyClass {
private:
    int privateData;
public:
    MyClass(int data) : privateData(data) {}
    friend class FriendClass; // FriendClass는 MyClass의 private member에 접근할 수 있음};

→ 마찬가지로, FriendClass 역시 MyClass '외부'에 정의되어 있음 

 

2-3. friend 함수와 friend 클래스를 모두 사용하는 경우

#include <iostream>

class FriendClass;

class MyClass {
private:
    int privateData;

public:
    MyClass(int data) : privateData(data) {}

    // FriendClass를 friend 클래스로 선언
    friend class FriendClass;

    void PrintPrivateData() {
        std::cout << "MyClass privateData: " << privateData << std::endl;
    }
};

class FriendClass {
private:
    int secretData;

public:
    FriendClass(int data) : secretData(data) {}

    void AccessMyClassPrivateData(MyClass& obj) {
        std::cout << "FriendClass accessing MyClass privateData: " << obj.privateData << std::endl;
    }
};

int main() {
    MyClass myObj(42);
    FriendClass friendObj(100);

    myObj.PrintPrivateData(); // MyClass의 멤버 함수를 통한 privateData 접근
    friendObj.AccessMyClassPrivateData(myObj); // FriendClass를 통한 privateData 접근

    return 0;
}

연산자 오버로딩에서 friend가 사용되는 사례

- 어떤 클래스에 이항 연산자를 오버로딩할 경우 friend 필요한 경우 발생함 (*이항 연산자 : 개의 피연산자를 요구하는 연산자)

 

(1) friend만을 이용해서 연산자 오버로딩 하는 경우

(단, 입력 매개변수가 'int * 클래스' 순서를 지켜야 함)

 

time.h

#include<iostream>
using namespace std;

#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H

class Time{
private:
    int hours;
    int mins;
public:
    Time();
    Time(int, int);
    void show();
    ~Time();
    
    friend Time operator*(int n, Time& t); //friend를 활용한 연산자 오버로딩
};

#endif //FIRE_C_TIME_H

time_func.cpp

#include "time.h"

Time::Time(){
    hours = 0;
    mins = 0;}

Time::Time(int h, int m){
    hours = h;
    mins = m;}

void Time::show(){
    cout << hours << "시간 " << mins << "분" << endl;}

Time::~Time(){}

// friend 통해 선언한 함수를 정의할 때
// 그것은 멤버함수가 아니므로 클래스 귀속 :: 표시도 하지 않고, friend를 명시하지도 않음
// 매개변수 입력 순서 중요
Time operator*(int n, Time& t){ //n*t로 해석됨 
    Time result;
    long resultMin = t.hours * n * 60 + t.mins * n;
    result.hours = resultMin / 60;
    result.mins = resultMin % 60;
    return result;
}

main.cpp

#include "time.h"
#include "time_func.cpp"

//c++ friend: public 이외에도 private 멤버변수에 접근할 수 있는 또 다른 방법
int main(){

    Time t1(1, 20);
    Time t2;
    Time t3;

    t2 = 3 * t1; //순서 바뀌면 안 됨
    t2.show();
    
    return 0;
}

(2) 사실.. 굳이 friend 쓰지 않아도 구현됨 (단, 입력 매개변수가 '클래스 * int' 순서를 지켜야 함)

 

time.h

#include<iostream>
using namespace std;

#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H

class Time{
private:
    int hours;
    int mins;
public:
    Time();
    Time(int, int);
    void show();
    ~Time();

    Time operator*(int n);
};

#endif //FIRE_C_TIME_H

time_func.cpp

#include "time.h"

Time::Time(){
    hours = 0;
    mins = 0;}

Time::Time(int h, int m){
    hours = h;
    mins = m;}

void Time::show(){
    cout << hours << "시간 " << mins << "분" << endl;}

Time::~Time(){}

// friend를 사용하지 않고 클래스의 멤버함수로 정의할 때
Time Time::operator*(int n){
    Time result;
    long resultMin = hours * n * 60 + mins * n;
    result.hours = resultMin / 60;
    result.mins = resultMin % 60;
    return result;
}

main.cpp

#include "time.h"
#include "time_func.cpp"

int main(){

    Time t1(1, 20);
    Time t2;

    t2 = t1 * 4;
    t2.show();

    return 0;
}

//5시간 20분

(3) 두 개의 입력 매개변수 순서를 자유롭게 하고 싶을 때 ~!

→ 그러면 friend 이용하는 경우와 이용하지 않는 경우 모두 활용하면 됨 (단순..)

 

time.h

#include<iostream>
using namespace std;

#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H

class Time{
private:
    int hours;
    int mins;
public:
    Time();
    Time(int, int);
    void show();
    ~Time();

    Time operator*(int n); //멤버함수
    friend Time operator*(int, Time&); //friend 함수
};

#endif //FIRE_C_TIME_H

time_func.cpp

#include "time.h"

Time::Time(){
    hours = 0;
    mins = 0;}

Time::Time(int h, int m){
    hours = h;
    mins = m;}

void Time::show(){
    cout << hours << "시간 " << mins << "분" << endl;}

Time::~Time(){}


// friend를 사용하지 않고 클래스의 멤버함수로 정의할 때
Time Time::operator*(int n){
    Time result;
    long resultMin = hours * n * 60 + mins * n;
    result.hours = resultMin / 60;
    result.mins = resultMin % 60;
    return result;
}

// friend 통해 선언한 함수를 정의할 때
// 그것은 멤버함수가 아니므로 클래스 귀속 :: 표시도 하지 않고, friend를 명시하지도 않음
Time operator*(int n, Time& t){
    return t*n;
}

main.cpp

#include "time.h"
#include "time_func.cpp"

int main(){

    Time t1(1, 20);
    Time t2;

    t2 = t1 * 4;
    t2.show();

    t2 = 4 * t1;
    t2.show();

    return 0;
}

/*5시간 20분
5시간 20분*/

 

728x90
728x90

1. 핵심 요약

1-1. 정의

연산자 오버로딩이란?

사용자 정의 데이터 타입(클래스)에 대한 연산자 동작을 redefine & expand

 C++ 객체 지향 프로그래밍의 핵심 원칙 하나인 다형성(polymorphism) 구현

 

- 다양한 연산자(예: +, -, *, /, ==, != 등)에 대해 사용됨

- 기존 연산자는 주로 특정 데이터타입에 국한되어 사용됨. 그러나 연산자 오버로딩을 통해, 사용자 정의 클래스의 객체를 일반적인 데이터 타입처럼 사용할 수 있음

 

*오류 방지하려면, 연산자의 의미와 클래스에 대한 연산 규칙을 명확히 이해해야

 

1-2. 연산자 오버로딩의 형식

- 연산자 오버로딩은 연산자(operator)를 정의한 클래스 내에서 진행됨

 

반환_타입 operator 연산자_이름(매개변수_목록) {

    // 연산을 정의한 코드

}

 

1-3. 연산자 오버로딩의 (일반화된?) 예시

- 클래스 내부에 연산자 오버로딩 정의

class Complex {
private:
    double real;
    double imag;

public:
    Complex(double r, double i) : real(r), imag(i) {}

    Complex operator+(const Complex& other) {
        return Complex(real + other.real, imag + other.imag);
    }
};

// Complex 클래스는 + 연산자를 오버로딩하여 두 개의 복소수를 더할 수 있도록 함.

- 연산자 오버로딩의 사용

Complex a(2.0, 3.0);
Complex b(1.0, 2.0);
Complex c = a + b; // + 연산자가 오버로딩되어 두 복소수를 더함

// a + b는 연산자 오버로딩된 + 연산자에 의해 두 Complex 객체가 더해짐

2. 구체적인 예시

2-1. 예시 요약

헤더파일에서

Time operator+(Time&);

함수 정의 파일에서

Time Time::operator+(Time& time){
    Time temp;
    temp.mins = mins + time.mins;
    temp.hours += temp.mins / 60;
    temp.mins %= 60;

    return temp;
}

main 파일에서

    Time total;
    total = day1.operator+(day2);

2-2. 예시 전문

 

1. time.h

#include<iostream>

#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H

using namespace std;

class Time{
private:
    int hours;
    int mins;
public:
    Time(); //클래스 생성자 //함수 오버로딩
    Time(int, int); //함수 오버로딩
    void addHours(int);
    void addMins(int);
//    Time sum(Time&);
    Time operator+(Time&);
    void show();
    ~Time(); //클래스 파괴자
};

#endif //FIRE_C_TIME_H

2. time_func.cpp

#include "time.h"

Time::Time(){
    hours = 0;
    mins = 0;
}

Time::Time(int h, int m) {
    hours = h;
    mins = m;
}

void Time::addHours(int h) {
    hours += h;
}

void Time::addMins(int m) {
    mins += m;
    hours += mins / 60;
    mins = mins % 60;
}

// Time Time::sum(Time& time){
//    Time temp;
//    temp.mins = mins + time.mins;
//    temp.hours += temp.mins / 60;
//    temp.mins %= 60;
//
//    return temp;
//}

Time Time::operator+(Time& time){
    Time temp;
    temp.mins = mins + time.mins;
    temp.hours += temp.mins / 60;
    temp.mins %= 60;

    return temp;
}

void Time::show(){
    cout << hours << "시간 " << mins << "분" << endl;
}

Time::~Time(){

}

3. main.cpp

#include "time.h"
#include "time_func.cpp"

int main() {
    Time day1(1, 40);
    Time day2(2, 30);

    day1.show();
    day2.show();

    //오버로딩한 연산자 사용 방법 (1)
    Time total;
    total = day1.operator+(day2);
    //기존에 만들었던 sum 함수 역할을 수행하는 연산자 오버로딩 하려면
    //함수 있던 자리에 'operator' , '오버로딩 할 연산자'의 연속으로 표현하면 됨

    //오버로딩한 연산자 사용 방법 (2)
    Time total2;
    total2 = day1 + day2; //혹은 아예 연산자만 사용해도 됨

    total.show();
    total2.show();

    return 0;
}

/*1시간 40분
2시간 30분
1시간 10분
1시간 10분*/

 

728x90
728x90

1) this 포인터

: 멤버함수를 호출하는 데 사용된 객체를 지시 (본질은 포인터 ; 주소값을 리턴)

 

#ifndef FIRE_C_STOCK_STRUCTURE_H
#define FIRE_C_STOCK_STRUCTURE_H
#include <iostream>
using namespace std;

class Stock {
private:
    string name;
    int shares;
    float share_val;
    double total_val; 
    void set_total() {total_val = shares * share_val;}

public:
    void show();
    Stock compare(Stock& stock);

    Stock(string, int, float); 
    Stock(); 
};

void Stock::show() {
    cout << "회사 명 : " << name << endl;
    cout << "주식 수 : " << shares << endl;
    cout << "주가 : " << share_val << endl;
    cout << "주식 총 가치 : " << total_val << endl << endl;
}

Stock Stock::compare(Stock& stock){
    if(stock.total_val >= total_val)
        return stock;
    else return *this; //this pointer //호출한 객체 자기 자신을 가리킴
}

Stock::Stock(string co, int n, float pr){
    name = co;
    shares = n;
    share_val = pr;
    set_total();
}

Stock::Stock(){
    name = "None";
    shares = 0;
    share_val = 0;
    set_total();
}
#endif //FIRE_C_STOCK_STRUCTURE_H
#include "stock_structure.h"

int main() {

    Stock temp = Stock("Panda", 100, 1000);
    Stock temp2("another", 200, 2000);
    temp.compare(temp2).show();
    return 0;}

/* 주식 총 가지가 더 높은 stock 클래스 객체가 출력됨
 * 
회사 명 : another
주식 수 : 200
주가 : 2000
주식 총 가치 : 400000*/

 

2) 클래스로 이루어진 배열

#include "stock_structure.h"

int main() {

    Stock s[4] = { //배열의 각 원소는 ;가 아닌 , 로 구분
            Stock("A", 10, 1000),
            Stock("B", 20, 2000),
            Stock("C", 30, 3000),
            Stock("D", 40, 4000)
    };

    Stock first = s[0]; //first: stock 배열에서 total이 가장 높은 것을 저장
    for(int i=1; i<4; i++)
        first = first.compare(s[i]);

    first.show();
    return 0;
}

→ 기존에 배열 만들고 활용하는 방식과 완전 동일함

 

**참조자 사용

#include "stock_structure.h"

int main() {

    Stock s[4] = { //배열의 각 원소는 ;가 아닌 , 로 구분
            Stock("A", 10, 1000),
            Stock("B", 20, 2000),
            Stock("C", 30, 3000),
            Stock("D", 40, 4000)
    };

    Stock* first = &s[0]; //값을 직접 대입하는 것이 아니라 주소로 참조하도록 함
    for(int i=1; i<4; i++)
        first = &first->compare(s[i]); //왜지왜지왜지왜지

    first->show();
    return 0;
}
#ifndef FIRE_C_STOCK_STRUCTURE_H
#define FIRE_C_STOCK_STRUCTURE_H
#include <iostream>
using namespace std;

class Stock {
private:
    //private member의 값을 변경하려면 public에 선언된 함수를 통해서만이 가능
    //private member에는 '직접' 접근할 수 없음 : 데이터 은닉
    string name;
    int shares;
    float share_val;
    double total_val; //double: float과 같이 실수를 표현하되 더 넓은 범위를 표현함
    void set_total() {total_val = shares * share_val;}
    //private에서 함수 포함 가능

public: //public member 함수: private member의 값을 변경할 수 있는 단위
    void show();
    Stock& compare(Stock&);

    Stock(string, int, float); //입력이 있는 생성자
    // 기존의 acquire 함수 대체 //클래스 생성할 때 init하는 것들
    Stock(); //Default 생성자
};

void Stock::show() {
    cout << "회사 명 : " << name << endl;
    cout << "주식 수 : " << shares << endl;
    cout << "주가 : " << share_val << endl;
    cout << "주식 총 가치 : " << total_val << endl << endl;
}

Stock& Stock::compare(Stock &stock){
    if(stock.total_val >= total_val)
        return stock;
    else return *this;
}

//Stock 클래스 내부에서 귀속되어 있음
/* 생성자 */
Stock::Stock(string co, int n, float pr){
    name = co;
    shares = n;
    share_val = pr;
    set_total();
}
/* Default 생성자 */
Stock::Stock(){
    name = "None";
    shares = 0;
    share_val = 0;
    set_total();
}
#endif //FIRE_C_STOCK_STRUCTURE_H

 

728x90
728x90

목차

0. 추상화란?

1. 클래스란?

2. 클래스 생성자

3. 클래스 파괴자


0. 추상화란?

- 어떠한 객체를 사실적으로 표현하는 것이 아니라, 공통된 특징을 간결한 방식으로, 이해하기 쉽게 표현하는 것

- c++에서 추상화 중요하다!

1. 클래스란?

- 추상화를 사용자 정의 데이터형으로 변환해주는 수단

- 같은 타입이면 서로 대입 가능 (마치 string)

 

1-1) stock_structure.h (헤더파일)

//클래스 선언 & 클래스 메서드 정의

#ifndef FIRE_C_STOCK_STRUCTURE_H
#define FIRE_C_STOCK_STRUCTURE_H
#include <iostream>
using namespace std;

class Stock {
private:
    //private member의 값을 변경하려면 public에 선언된 함수를 통해서만이 가능
    //private member에는 '직접' 접근할 수 없음 : 데이터 은닉
    string name;
    int shares;
    float share_val;
    double total_val; //double: float과 같이 실수를 표현하되 더 넓은 범위를 표현함
    void set_total() {total_val = shares * share_val;}
    //private에서 함수 포함 가능

public: //public member 함수: private member의 값을 변경할 수 있는 단위
    void acquire(string, int, float);
    void buy(int, float);
    void sell(int, float);
    void update(float);
    void show();
};

//사용 범위 결정 연산자 ::
void Stock::acquire(string co, int n, float pr) {
    name = co;
    shares = n;
    share_val = pr;
    set_total();
}

void Stock::buy(int n, float pr) {
    shares += n;
    share_val += pr;
    set_total();
}

void Stock::sell(int n, float pr) {
    shares -= n;
    share_val -= pr;
    set_total();
}

void Stock::update(float pr) {
    share_val = pr;
    set_total();
}

void Stock::show() {
    cout << "회사 명 : " << name << endl;
    cout << "주식 수 : " << shares << endl;
    cout << "주가 : " << share_val << endl;
    cout << "주식 총 가치 : " << total_val << endl;
}

#endif //FIRE_C_STOCK_STRUCTURE_H

1-2) main.cpp 소스파일

#include "stock_structure.h"

int main() {

    Stock temp;
    temp.acquire("Panda", 100, 1000);
    temp.show();
    temp.buy(10, 1200);
    temp.show();
    temp.sell(5, 800);
    temp.show();

    return 0;}

/*회사 명 : Panda
주식 수 : 100
주가 : 1000
주식 총 가치 : 100000
회사 명 : Panda
주식 수 : 110
주가 : 2200
주식 총 가치 : 242000
회사 명 : Panda
주식 수 : 105
주가 : 1400
주식 총 가치 : 147000*/

2. 클래스 생성자

2-1) 클래스 생성자 & default 클래스 생성자가 추가된 stock_structure.h

- 기존의 acquire함수 코드를 생성자 코드에 반영

- 생성자는 클래스 내 원형 선언 시 자료형을 쓰지 않아도 됨. 클래스 이름 그대로 사용.

#ifndef FIRE_C_STOCK_STRUCTURE_H
#define FIRE_C_STOCK_STRUCTURE_H
#include <iostream>
using namespace std;

class Stock {
private:
    //private member의 값을 변경하려면 public에 선언된 함수를 통해서만이 가능
    //private member에는 '직접' 접근할 수 없음 : 데이터 은닉
    string name;
    int shares;
    float share_val;
    double total_val; //double: float과 같이 실수를 표현하되 더 넓은 범위를 표현함
    void set_total() {total_val = shares * share_val;}
    //private에서 함수 포함 가능

public: //public member 함수: private member의 값을 변경할 수 있는 단위
    void show();
    Stock(string, int, float); //입력이 있는 생성자
    // 기존의 acquire 함수 대체 //클래스 생성할 때 init하는 것들
    Stock(); //Default 생성자
    ~Stock(); //파괴자
};

void Stock::show() {
    cout << "회사 명 : " << name << endl;
    cout << "주식 수 : " << shares << endl;
    cout << "주가 : " << share_val << endl;
    cout << "주식 총 가치 : " << total_val << endl << endl;
}

//Stock 클래스 내부에서 귀속되어 있음
/* 생성자 */
Stock::Stock(string co, int n, float pr){
    name = co;
    shares = n;
    share_val = pr;
    set_total();
}
/* Default 생성자 */
Stock::Stock(){
    name = "None";
    shares = 0;
    share_val = 0;
    set_total();
}

/* 파괴자 */
Stock::~Stock(){

}
#endif //FIRE_C_STOCK_STRUCTURE_H

 

2-2) 클래스 생성자 & default 클래스 생성자가 호출된 main.cpp 소스파일

#include "stock_structure.h"

int main() {

    Stock temp = Stock("Panda", 100, 1000);
    Stock temp2("another", 200, 2000);
    Stock temp3; //default 생성자 //함수 오버로딩 사용
    temp.show();
    temp2.show();
    temp3.show();
    return 0;}

/*회사 명 : Panda
주식 수 : 100
주가 : 1000
주식 총 가치 : 100000

회사 명 : another
주식 수 : 200
주가 : 2000
주식 총 가치 : 400000

회사 명 : None
주식 수 : 0
주가 : 0
주식 총 가치 : 0*/

2-2-0) 클래스 생성자의 특징

리턴값을 가지지 않고 & 자료형이 별도로 없음

 

2-2-1) 클래스 생성자로 생성하는 방법에는 두 가지가 있음

(1) 클래스타입 클래스명 = 클래스타입(입력)

(2) 클래스타입 클래스명(입력)

 

2-2-2) Default 클래스 생성자는 '함수 오버로딩' 컨셉을 사용하는 것

** 생성자

Stock::Stock(string co, int n, float pr){

    name = co;

    shares = n;

    share_val = pr;

    set_total(); }

 

** Default 생성자

Stock::Stock(){

    name = "None";

    shares = 0;

    share_val = 0;

    set_total(); }


3. 클래스 파괴자

3-1) 클래스 파괴자의 특징

생성자의 반대. 객체의 수명이 끝나는 시점에서 파괴자가 자동으로 호출됨. (사용자가 직접 할 수 없음)

- 클래스 생성자와 마찬가지로 리턴값을 가지지 않고 & 자료형이 따로 없으며

- 추가로, 매개변수 입력을 가지지 않음

- 파괴하는 것 이외 아무것도 하는 일이 없으므로, 내부 코드가 필요 없음

 

3-2) 파괴자가 자동으로 호출되는 세 가지 경우

1) 스코프를 벗어났을때

2) new를 사용하여 객체를 생성하고 delete 하였을때

3) 임시 객체를 생성했을 경우에 프로그램은 객체의 사용을 마쳤을때

 

3-3) 파괴자가 필요한 이유

만약 클래스 내부에서 동적할당이 일어난다면 메모리 해제도 필요함. C++에서 메모리 관리는 직접 해야하기 때문임.
파괴자가 호출됐다는 건, 더이상 그 객체가 쓰이지 않는다는것. 따라서 메모리 해제를 해야 메모리 누수(memory leak)이 발생하지 않음.
//헤더파일에서

public: //public member 함수: private member의 값을 변경할 수 있는 단위
    void show();
    Stock(string, int, float); 
    Stock(); 
    ~Stock(); //파괴자
};
// ... 헤더파일에서 

///* 파괴자 */
Stock::~Stock(){
cout << name << " 클래스가 소멸되었습니다.\n" << endl;
}

main.cpp 실행 결과

>>>

회사 명 : Panda
주식 수 : 100
주가 : 1000
주식 총 가치 : 100000

회사 명 : another
주식 수 : 200
주가 : 2000
주식 총 가치 : 400000

회사 명 : None
주식 수 : 0
주가 : 0
주식 총 가치 : 0

None 클래스가 소멸되었습니다.

another 클래스가 소멸되었습니다.

Panda 클래스가 소멸되었습니다.

 

 

Refer to

https://inf.run/31sv

https://blog.plorence.dev/502

728x90

+ Recent posts