gugbab2's GitBook
  • Language
    • C++
      • 강의
        • C++ 언매니지드 프로그래밍
          • C++ 프로그래밍
          • 출력(Output)
          • 입력(Input)
          • bool 타입, Reference
          • 상수(const)
          • 문자열(string)
          • 파일 입출력
          • 개체지향 프로그래밍1
          • 개체지향 프로그래밍2
          • 개체지향 프로그래밍3
          • 캐스팅(형변환, casting)
          • 인라인 함수
          • static 키워드
          • 예외(Exception)
          • STL(Standard Template Library) 컨테이너(Container) - Vector
          • STL 컨테이너 - Map
          • STL 컨테이너 - Queue, Stack, Set, List
          • 템플릿(Template) 프로그래밍
          • 새로운 키워드(C++11 ~) 1
          • 새로운 키워드(C++11 ~) 2
          • 새로운 자료형
          • 새로운 STL 컨테이너
          • 스마트(smart) 포인터
          • 이동생성자 및 이동대입연산자
          • constexpr
          • Lamda Expression
      • 책
        • The C++ Programming Lanuaage
          • 2부 : 기본 기능
            • 6. 타입과 선언
            • 7. 포인터, 배열, 참조
            • 8. 구조체(struct), 공용체(union), 열거형(enum)
            • 10. 표현식
            • 11. 선택 연산
            • 12. 함수
            • 13. 예외 처리
            • 15. 소스 파일과 프로그램
          • 3부 : 추상화 메커니즘
            • 16. 클래스
            • 17. 생성, 소멸, 복사와 이동
            • 18. 연산자 오버로딩
            • 19. 특수 연산자
            • 20. 파생클래스
        • 씹어먹는 C++
          • 2. C++ 참조자(reference) 의 도입
          • 5.1 연산자 오버로딩(비교, 대입 연산자)
          • 5-2. 연산자 오버로딩(이항, 입출력, 타입변환, 증감 연산자)
          • 6-2. 가상(virtual) 함수와 다형성
          • 6-3. 가상 함수에 대한 지식들
          • 9-1. 코드를 찍어내는 틀 - C++ 템플릿(template)
          • 9-2. 가변 길이 템플릿(Variadic template)
          • 9-3. 템플릿 메타 프로그래밍 (Template Meta Programming)
          • 9-4. 템플릿 메타 프로그래밍2
          • 16.1 유니폼 초기화(Uniform Initialization)
          • 토막글 2. 람다(lambda)
    • Java
      • 강의
        • 김영한의 실전 자바 - 기본편
          • 절차 지향 vs 객체 지향
            • 절차 지향 프로그래밍
            • 객체 지향 프로그래밍
          • 변수
            • 클래스 변수 / 인스턴스 변수, 멤버 변수 / 지역 변수
            • 기본형 vs 참조형
          • 패키지
            • 패키지
            • CLI 환경에서 .java 파일 컴파일 && 실행
          • 접근 제어자
            • 접근 제어자 - 기본
            • 캡슐화
          • static
            • 자바 메모리 구조
            • static 기본
            • 스택 영역, 힙 영역
              • 스택 영역, 힙 영역 - 기본
              • 메소드가 실행될 때 어떤일이 일어나는가?
          • 상속
            • 상속 기본
          • 다형성(Pilymorphism)
            • 다형성 기본
            • 다형성의 활용
              • 다형성의 활용 - 기본
              • 다형성의 활용 - 추상클래스
              • 다형성의 활용 - 인터페이스
            • 다형성과 설계
              • 좋은 객체 지향 프로그래밍
        • 김영한의 실전 자바 - 중급1편
          • 1. Object 클래스
          • 2. 불변 객체
          • 3. String 클래스
          • 4. 래퍼, Class 클래스
          • 5. 열거형 - ENUM
          • 6. 날짜와 시간
          • 7. 중첩 클래스, 내부 클래스1
          • 8. 중첩 클래스, 내부 클래스2
          • 9. 예외 처리1 - 이론
          • 10. 예외 처리 - 실습
        • 김영한의 실전 자바 - 중급2편
          • 1. 제네릭 - Generic1
          • 2. 제네릭 - Generic2
          • 3. 컬렉션 프레임워크 - ArrayList
          • 4. 컬렉션 프레임워크 - LinkedList
          • 5. 컬렉션 프레임워크 - List
          • 6. 컬렉션 프레임워크 - 해시(Hash)
          • 7. 컬렉션 프레임워크 - HashSet
          • 8. 컬렉션 프레임워크 - Set
            • 레드 블랙 트리
          • 9. 컬렉션 프레임워크 - Map, Stack, Queue
            • 왜(?) Set 은 내부에서 Map 을 사용할까?
          • 10. 컬렉션 프레임워크 - 순회, 정렬, 전체 정리
        • 김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
          • 프로세스와 스레드 소개
          • 스레드 생성과 실행
          • 스레드 제어와 생명 주기1
          • 스레드 제어와 생명 주기2
          • 메모리 가시성
          • 동기화 - synchronized
            • synchronized 키워드 이해도 체크
          • 고급 동기화 - concurrent.Lock
          • 생산자 소비자 문제1
          • 생산자 소비자 문제2
          • CAS - 동기화와 원자적 연산
          • 동시성 컬렉션
          • 스레드 풀과 Executor 프레임워크1
          • 스레드 풀과 Executor 프레임워크2
        • 김영한의 실전 자바 - 고급 2편, I/O, 네트워크, 리플렉션
          • 문자 인코딩
          • I/O 기본1
          • I/O 기본2
          • I/O 활용
          • File, Files
          • 네트워크 - 프로그램1
          • 네트워크 - 프로그램2
          • 채팅 프로그램
          • HTTP 서버 만들기
          • 리플렉션
          • 애노테이션
          • HTTP 서버 활용
        • 김영한의 실전 자바 - 고급3편, 람다, 스트림, 함형 프로그래밍
          • 람다가 필요한 이유
          • 람다
          • 함수형 인터페이스
          • 람다 활용
          • 람다 vs 익명 클래스
          • 메서드 참조
          • 스트림API1 - 기본
          • 스트림 API2 - 기능
          • 스트림 API3 - 컬렉터
          • Optional
          • 디폴트 메서드
          • 병렬 스트림
          • 함수형 프로그래밍
        • 기초 탄탄! 독하게 시작하는 Java - Part2: OOP 와 JVM
          • 2. 클래스 - 첫 번째
          • 3. 클래스 - 두번째
          • 4. 상속과 관계
          • 6. JVM(Java Virtual machine) 기본 이론
          • 7. JVM 과 GC 그리고 객체
          • 8. 불변 객체와 String 클래스
      • 책
        • 자바의 신
          • 변수
            • 클래스 변수(static) 사용 주의 케이스
            • Java volatile 과 Atomic 변수(+CAS)
          • 연산자
            • 비트 연산자 활용 예제
          • 배열
          • 참조 자료형
          • 상속
          • Object 클래스
          • interface, abstract class, enum
          • 예외
          • String 클래스
            • String 구조
            • String 문자열을 byte 로 변환하기
            • String 클래스에서 자주 사용되는 메서드
            • String 클래스로 살펴보는 불변(Immutable)객체
            • StringBuilder, StringBuffer
          • Nested 클래스
          • 어노테이션
            • 어노테이션 기본
            • 어노테이션의 사용
          • JVM 이해하기
            • 왜 JVM 을 사용해?
            • JVM, JRE, JDK
            • JVM 구조 이해하기
            • 클래스 로더 시스템
            • JIT(Just-In-Time) 컴파일러
            • GC(Garbage Collector)
              • GC Part.1
              • GC Part.2
              • GC 튜닝
          • java.lang
            • Wrapper 클래스
            • System 클래스
          • Generic
            • 제네릭 기본
            • 와일드카드
            • 와일드카드 GET / SET 경계
            • 와일드카드 extends / super 사용시기
            • 혼동할 수 있는 와일드카드 표현
          • Collection
            • 자료구조
              • 이진 탐색 트리 vs 레드 블랙 트리
            • Collection
            • List
              • ArrayList
              • Vector
              • Stack
              • LinkedList
            • Set, Queue
              • HashSet
              • LinkedHashSet
              • TreeSet
              • Priority Queue
              • ArrayDeque
            • Map
              • HashMap
              • Hashtable
              • LinkedHashMap
              • TreeMap
          • Thread
            • Thread 기본
            • Thread 와 관련이 많은, Synchronized
            • Thread 를 통제하는 메서드
            • ThreadGroup
          • I/O
            • InputStream, OutputStream
            • Reader, Writer
          • Serializable, NIO
            • Serializable
            • NIO (New IO)
          • 네트워크 프로그래밍
            • 네트워크 기본 & TCP 통신
            • UDP 통신
          • 람다
            • 함수형 인터페이스
            • 람다란?
        • 벨둥(Bealdung)
          • Java Concurrency
            • Java Concurrency Basics
              • Overview of the java.util.concurrent
              • Guide to the Synchronized Keyword in Java
              • Guide to the Volatile Keyword in Java
              • Guide to the java.util.concurrent.Future
              • ThreadLocal in Java
      • 그 외
        • 시스템 콜과 자바에서의 시스템 콜 사용례
        • 자바 NIO 의 동작원리 및 IO 모델
        • 함수형 인터페이스(FunctionInterface) - 자바8
  • Spring
    • 강의
      • 스프링 핵심 원리 - 기본편
        • 큰 흐름 잡기
        • 스프링 핵심 원리 이해1 - 예제 만들기
        • 스프링 핵심 원리 이해2 - 객체 지향 원리 적용
        • 스프링 컨테이너와 스프링 빈
        • 싱글톤 컨테이너
        • 컴포넌트 스캔
        • 의존관계 자동 주입
        • 빈 생명주기 콜백
        • 빈 스코프
      • 토비의 스프링6 - 이해와 원리
        • 3. 오브젝트와 의존관계1
        • 3. 오브젝트와 의존관계2
        • 4. 테스트
        • 5. 템플릿
        • 6.예외
        • 7. 서비스 추상화
    • 책
      • JSP 2.3 웹 프로그래밍
        • Servlet
        • JSP
        • 쿠키 / 세션
        • MVC 패턴
        • 실무 때 고민할 만한 부분
      • 스프링 입문을 위한 자바 객체지향의 원리와 이해
        • 자바와 절차적/구조적 프로그래밍
        • 객체지향의 4대 특성
        • 객체지향 설계의 5원칙
        • 스프링이 사랑한 디자인 패턴
        • IoC / DI
        • AOP(Aspect Oriented Programming), 관점 지향 프로그래밍
      • 토비의 스프링 3.1
        • Spring vs Spring Boot
        • 1. 오브젝트와 의존관계
          • 1.4 제어의 역전(IoC)
          • 1.5 스프링의 IoC
          • 1.6 싱글톤 레지스트리와 오브젝트 스코프
    • 그 외
      • 스프링 부트(SpringBoot) 탄생 배경
  • CS
    • DATA STRUCTURES
      • 선택 정렬(Selection Sort)
      • 버블 정렬(Bubble Sort)
      • 삽입 정렬(Insertion Sort)
    • OS
      • 강의
      • 책
        • 혼자 공부하는 컴퓨터구조 + 운영체제
          • 1. 컴퓨터 구조 시작하기
          • 2. 데이터
          • 3. 명령어
          • 4. CPU 의 작동원리
          • 5. CPU 성능 향상 기법
          • 6. 메모리와 캐시메모리
          • 7. 보조기억장치
          • 8. 입출력장치
          • 9. 운영체제 시작하기
          • 10. 프로세스와 스레드
    • NETWORK
      • 그 외
        • REST API
          • REST API
          • URI & MIME type
          • Collection Pattern
          • Collection Pattern 적용
          • Spring Web MVC 구현
        • SSL 인증 동작
        • DTO & JSON & CROS
          • DTO
          • 직렬화(Serialization)
          • Jackson ObjectMapper
          • CROS
        • Connection Timeout / Read Timeout
      • 강의
        • 외워서 끝내는 네트워크 핵심이론 - 기초
          • Internet 기반 네트워크 입문
            • Host 는 이렇게 외우자
            • 스위치가 하는 일과 비용
          • L2 수준에서 외울 것들
            • NIC, L2 Frame, LAN 카드 그리고 MAC 주소
            • L2 스위치에 대해서
            • LAN 과 WAN 의 경계 그리고 Broadcast
          • L3 수준에서 외울 것들
            • IPv4 주소의 기본 구조
            • L3 IP Packet 으로 외워라
            • 패킷의 생성과 전달 및 계층별 데이터 단위
            • 이해하면 인생이 바뀌는 TCP/IP 송, 수신 구조
            • IP 헤더 형식
            • 서브넷 마스크와 CIDR
            • Broadcast IP 주소와 Localhost
            • TTL 과 단편화
            • 인터넷 설정 자동화를 위한 DHCP
            • ARP 과 Ping(RTT : Round Trip Time)
          • L4 수준 대표주자 TCP 와 UDP
            • TCP 와 UDP 개요
            • TCP 연결 및 상태 변화
            • TCP 연결 종료 및 상태 변화
            • TCP, UDP 헤더 형식과 게임서버 특징
            • TCP 가 연결이라는 착각
            • TCP 연결과 게임버그
          • 웹을 이루는 핵심기술
            • DNS
            • URL, URI
        • 외워서 끝내는 네트워크 핵심 이론 - 응용
          • 네트워크 장치의 구조
            • 세 가지 네트워크 장치 구조
            • Inline 구조
            • Out of path 구조와 DPI 그리고 망중립
            • Proxy(클라이언트 입장) - 우회
            • Proxy(클라이언트 입장) - 보호와 감시
            • Reverse Proxy(서버 입장)
          • 인터넷 공유기의 작동 원리
            • 공유기 개요
            • Symmetric NAT
            • Full Cone 방식
            • Restricted Cone, Port Restricted Cone
            • 포트 포워딩
            • UPnP 와 NAT
          • 부하분산 시스템 작동 원리
            • L4 부하분산 무정지 시스템
            • 대규모 부하분산을 위한 GSLB
          • VPN과 네트워크 보안 솔루션
            • PN 과 VPN
            • IPSec VPN 과 터널링 개념
            • VPN 과 재택근무
        • 외워서 끝내는 SSL 과 최소한의 암호기술
          • 기초이론
            • Checksum (검사합)
            • Hash
          • 암호기술에 대한 이해
            • 대칭키
            • 비대칭키
          • PKI 시스템과 인터넷
            • 인터넷을 위한 비대칭키 체계
            • 공개키 신뢰를 위한 검증체계
            • 웹서비스와 공인인증서
      • 책
        • 그림으로 배우는 네트워크 원리
          • 1. 네트워크 기본
          • 2. 네트워크를 만드는 것
          • 3. 네트워크의 공통 언어 TCP/IP
    • SECURITY
      • 그 외
        • Basic Auth
        • HMAC 기반 인증
    • 그 외
      • 동기/비동기 & 블로킹/논블록킹
  • DB
    • 그 외
      • 인덱스(Index)
      • 트랜잭션(TRANSACTION)
      • 실무에서 외래키를 사용하지 않는 이유
      • ORM vs SQL Mapper
      • 문자열 vs DATE
      • EXPLAIN 명령어
    • 강의
      • Real MySQL 시즌 1
        • Part.1
          • 1강. CHAR vs VARCHAR
          • 2강. VARCHAR vs TEXT
          • 3강. COUNT(*) & COUNT(DISTINCT) 튜닝
          • 4강. 페이징 쿼리 작성
          • 5강. Stored Function
      • 토크온 41차. JPA 프로그래밍 기본 다지기
        • 1. JPA 소개
        • 2. JPA 기초와 매핑
        • 3. 필드와 컬럼 매핑
        • 4. 연관관계 매핑
        • 5. 양방향 매핑
        • 6. JPA 내부구조
        • 7. JPA 객체지향쿼리
        • 8. Spring Data JPA 와 QueryDSL 이해
    • 책
  • Software Development Methodology
    • TDD
      • 강의
        • Spring Boot TDD - 입문부터 실전까지 정확하게
          • 세션2. TDD 소개
          • 세션5. API 설계
          • 세션6. TDD 주기 첫 번째 경험
          • 세션7. TDD 주기 반복
      • 그 외
        • 단위 테스트(Unit Test) 작성의 필요성
        • JUnit5
          • A Guide to JUnit 5
          • Guide to JUnit 5 Parameterized Tests
          • AssertJ Exception Assertions
          • Testing in Spring Boot
          • Junit 과 Mockito 기반의 Spring 단위 테스트 코드 작성법
        • Code Coverage
          • Code Coverage?
    • DDD
      • 책
        • 도메인 주도 설계(Domain-Driven Design)
          • 04 - 도메인의 격리
          • 05 - 소프트웨어에서 표현되는 모델
          • 06 - 도메인 객체의 생명주기
          • 07 - 언어의 사용(확장 예제) (1)
          • 07 - 언어의 사용(확장 예제) (2)
        • 도메인 주도 개발 시작하기
          • 1. 도메인 모델 시작하기
          • 2. 아키텍처 개요
          • 3. 애그리거트
          • 4. 리포지터리와 모델 구현
            • DAO vs Repository
      • 강의
        • DDD 세레나데(NEXTSTEP)
          • 1주차
            • 도메인 주도 설계 등장 배경
            • 레거시 코드
            • 유연한 설계 - ASSERTION
          • 2주차
            • 전략적 설계 - UBIQUITOUS LANGUAGE
            • 전략적 설계 - BOUNDED CONTEXT
          • 3주차
            • 전술적 설계 - VALUE OBJECT 와 ENTITY
            • 전술적 설계 - AGGREGATE 와 REPOSITORY
            • 전술적 설계 - SERVICE
    • REFACTORING
      • 일급 컬렉션(First Class Collection) 소개와 사용해야하는 이유
  • ARCHITECTURE
    • Event Driven Architecture
  • 멘토링
    • F-Lab
      • 10회차(2024.12.29)
Powered by GitBook
On this page
  • 16.2 클래스 기초
  • 16.2.1 멤버 함수
  • 16.2.2 기본 복사
  • 16.2.4 class 와 struct
  • 16.2.5 생성자
  • 16.2.6 explicit 생성자
  • 16.2.7 클래스 내 초기화 식
  • 16.2.8 클래스 내 함수 정의
  • 16.2.9 가변성
  • 16.2.10 자기 참조
  • 16.2.11 멤버 접근
  • 16.2.12 static 멤버
  • 16.2.13 멤버 타입
  • 16.3 구체 클래스
  1. Language
  2. C++
  3. 책
  4. The C++ Programming Lanuaage
  5. 3부 : 추상화 메커니즘

16. 클래스

클래스는 기본 제공 타입처럼 편리하게 쓰일 수 있는 새로운 타입을 생성하는 수단이다.

16.2 클래스 기초

클래스를 아주 간단히 요약하면 다음과 같다.

  • 클래스는 사용자 정의 타입이다.

  • 클래스는 멤버의 집합으로 구성된다. 가장 흔한 종류는 멤버 변수와 멤버 함수이다.

  • 멤버 함수는 초기화, 복사, 이동, 소멸의 의미를 정의할 수 있다.

  • 개체에 대해서는 . 과 -> 를 이용해 멤버에 접근할 수 있다.

  • +, !, [] 등의 연산자는 어떤 클래스도 오버라이딩 할 수 있다.

  • 클래스는 멤버가 포함된 네임스페이스이다.

  • public 멤버는 클래스의 인터페이스를 제공하고, private 멤버는 구현 세부 사항을 제공한다.

  • struct 는 public 멤버가 기본인 클래스이다.

16.2.1 멤버 함수

  • 클래스 정의 안에 있는 함수를 멤버 함수라고 부르며, 멤버 함수 내에서는 개체를 명시적으로 가리키지 않고 멤버 이름을 사용할 수 있다.

16.2.2 기본 복사

  • 개체는 기본적으로 복사 될 수 있다. -> 특히 클래스 개체는 그것의 클랫스 개체의 사본으로 초기화 할 수 있다.

Date d1 = my_birthday;    // 복사에 의한 초기화 
Date d2 {my_birthday};    // 복사에 의한 초기화

16.2.4 class 와 struct

  • class 와 struct 의 차이점은 다음과 같다.

    • class 의 기본 접근제어자는 private

    • struct 의 기본 접근제어자는 public

  • 때문에 아래 코드는 같은 의미를 가지고 있다.

struct S {}
class S {public : }
  • 위 두가지 정의는 서로 바꾸어 사용할 수 있지만, 그래도 한 가지 스타일을 고수하는 편이 대개는 바람직하다.

  • 어떤 스타일을 고수하는지는 보통은 환경 또는 개인의 선택에 달려있다. -> 필자는 '단순한 데이터 구조' 에 대해서는 struct -> 어떤 개체가 불변 속성을 가지는 것이 적합하다고 생각될 때 class 를 사용한다. (불변 속성을 가지는 것에 적합 : 생성자에서 맴버변수를 초기화 해야할 때?)

16.2.5 생성자

  • 클래스 개체 생성 시 호출되는 함수를 생성자라고 부른다. -> 생성자는 개체의 적절한 초기화를 보장하므로써 멤버 함수의 구현을 대폭 단순화해준다.

  • 생성자는 클래스 초기화를 정의하는 것이므로, {} 표기를 사용할 수도 있다.

  • 개체 생성 시 () 보다는 {} 를 사용한 초기화가 권장되는데 이유는 다음과 같다.

    • 통일된 초기화 방식

    • Narrowing Conversion 방지

    • 모호성 방지

      • {} 는 함수 사용과 개체 초기화 사이의 모호성을 방지한다. -> {} 는 개체 초기화에서 사용이 가능하다.

  • 생성자는 통상적인 함수가 준수하는 똑같은 오버로딩 규칙을 준수한다.

16.2.6 explicit 생성자

  • 생성자 호출에서 암시적 형변환이 많은 경우 상당한 혼란과 오류의 원인이 될 수 있다.

  • 아래 코드는 15 와 Date 사이에 명확한 논리적 연결 관계가 존재하지 않는다.

void my_fct(Date d);
void f()
{
    Date d {15};   // 그럴 듯해 보인다. - x는 {15, today.m, today.y} 가 된다. 
    // ... 
    my_fct(15);    // 모호하다. 
    d = 15;        // 모호하다. 
}
  • 다행스럽게도 explicit 생성자를 통해서 암시적 변환으로 생성자를 호출하지 않게 할 수 있다.

  • 아래 코드를 살펴보면, = 사용한 복사 초기화에서는 explicit 생성자를 사용할 수 없다.

  • 기본적으로 단일 인자로 초기화 될 수 있는 생성자는 explicit 로 선언되어야 한다. -> 그렇지 않다면 그렇지 않은 이유를 문서화 해 놓는 것이 바람직하다.

class Date {
    int d, m, y;
public :
    explicit Date (int dd=0, int mm=0, int yy=0);
    //...
};

void my_fct(Date d);

Date d1{15};            // ok 
Date d2 = Date{15};     // ok
Date d3 = {15};         // error : = 초기화로 암시적 변환이 수행되지 않는다. 
Date d4 = 15;           // error : = 초기화로 암시적 변환이 수행되지 않는다. 

void f()
{
    my_fct(15);         // error : 인자 전달로 암시적 변환이 수행되지 않는다. 
    my_fct({15});       // error : 인자 전달로 암시적 변환이 수행되지 않는다. 
    my_fct(Date{15});   // ok
}

16.2.7 클래스 내 초기화 식

  • 여러 개의 생성자를 사용할 때 초기화 로직이 반복될 수 있다. 이를 해결하기 위해서 다음의 방법을 사용할 수 있다.

    • 기본 인자를 도입

    • 공통적인 초기화 부분을 처리하는 생성자에게 넘기는 방식

    • 멤버 변수에 초기화 식을 추가하는 방식

  • 아래 코드에서 '멤버 변수에 초기화 식을 추가하는 방식 ' 을 구현해 보았는데, 각 생성자가 직접 초기화하지 않아도 d,m,y 는 초기화된다.

// 멤버 변수에 초기화 식을 추가하는 방식 
struct {int d, m, y;} date_initializer = {1,1,1970};
class Date {
    int d {date_initializer.d};
    int m {date_initializer.m};
    int y {date_initializer.y};
public :
    Date (int, int, int);
    Date (int, int);
    Date (int);
    Date ();
    Date (const char*); 
}

16.2.8 클래스 내 함수 정의

  • 클래스 내 정의된 멤버 함수는 인라인 멤버 함수로 정의 된다. -> 즉, 클래스 내 멤버 함수 정의는 작고, 거의 변경되지 않으며, 빈번히 사용되는 함수를 위한 것이다. -> 인라인 멤버 함수로 정의 될 시 함수 호출 비용이 발생하지 않는다.

    • 컴파일러가 멤버 함수의 내용이 적다고 생각되면 인라인으로 아니라면 그냥 멤버 함수의 형태로 사용한다. (선택적이다)

  • 다음의 코드는 동일하게 동작한다.

// 클래스 내 함수 정의 
class Date {
public : 
    void add_month (int n) {m+=n};
    // ...
private : 
    int d, m, y;
};

// 인라인 멤버 함수 정의 
class Date{
public : 
    void add_month(int n);
    // ...
private : 
    int d, m, y;
};
inline void Date::add_month(int n)
{
    m+=n;
}

16.2.9 가변성

16.2.9.1 상수 멤버 함수

  • const 를 이용해 멤버 함수가 멤버 변수의 값을 변환하지 않도록 선언할 수 있다. -> 멤버 변수를 변환한다면 컴파일 에러가 발생한다.

class Date {
    int d, m, y;
public : 
    int day() const {return d;}
    int month() const {return m;}
    int year() const {return y;}
    
    void add_year(int n);
    // ...
}

16.2.9.2 물리적 및 논리적 상수성 (logical constness)

  • 경우에 따라서 멤버 함수가 논리적으로는 const 지만, 여전히 멤버의 값을 변경할 필요가 있을 때가 있다. -> 즉, 사용자에게는 함수가 개체의 상태를 변경하지 않는 것처럼 보이지만, 사용자가 직접적으로 인지할 수 없는 어떤 세부사항이 갱신될 수 있다. -> 이를 가리켜 '논리적 상수성'(logical constness) 이라고 부른다.

  • 이런 표현은 상대적으로 비용이 많이 드는 연산일 수 있다. -> 따라서 Date 의 값이 변경되지만 않는다면 사본을 하나 만들어놓고, 반복되는 요청에 대해 이 사본만 반환하는 방식이 타당할 수 있다.

  • 아래의 코드를 보자

    • 사용자 관점에서 보면 string_rep 은 Date 의 상태를 변경하지 않는다.

    • 반면, mutable 선언을 통해서 아래 cache_valied, cache 는 string_rep() 에서 변경될 수 있다.

class Date {
public :
    string string_rep() const;
    // ...
private : 
    mutable bool cache_valied;
    mutable string cache;
    void compute_cache_value();    
};    

16.2.9.3 mutable

  • 멤버 변수를 mutable 로 선언할 수 있는데, 이는 해당 멤버가 const 개체 내에서도 수정될 수 있다는 것을 의미한다.

class Date {
public :
    string string_rep() const;
    // ...
private : 
    mutable bool cache_valied;
    mutable string cache;
    void compute_cache_value();      // 캐시의 값을 계산
}; 

void f(Date d, const Date cd)
{
    string s1 = d.string_rep();
    string s2 = cd.string_rep();     // OK : 멤버변수가mutable 로 선언되었다.
    // ... 
}

16.2.9.4 간접 참조를 통한 가변성

  • 어떤 멤버 변수를 mutable 로 선언하는 것은 소규모 개체 표현의 작은 부분에 대해서만 변경이 허용 될 때 가장 적합하다.

  • 좀 더 복잡한 경우에는 변경되는 데이터를 별도에 개체에 넣고 간접적으로 접근하는 방식이 다루기 편하다.

  • 위 코드는 간접 참조를 사용 시 아래와 같이 변경된다.

struct cache {
    bool valid; 
    string rep;
};

class Date {
public : 
    // ...
    string string_rep() const;    
private : 
    cache* c;                            // 생성자에서 캐시 초기화
    void compute_cache_value() const;    // 캐시의 값을 계산
    // ...
};

string Date::string_rep() const 
{
    if(!c->valid) {
        compute_cache_value();
        c->valid = true;
    }
    
    return c->rep;
}

16.2.10 자기 참조

  • 클래스의 연산들이 연결되도록 하고 싶다면 개체에 대한 참조자를 리턴하면 된다.

  • 아래 코드를 살펴보자

class Date {
    // ...
    Date& add_year(int n);
    Date& add_month(int n); 
    Date& add_day(int n);
}

void f(Date& d) 
{
    // ...
    d.add_year(1).add_month(1).add_year(1);
}
  • 함수 내에서 자기 참조를 리턴하기 위해서는 this* 를 사용할 수 있다. -> this 는 현재 개체의 포인터이고, -> this* 는 현재 개체의 참조이다.

  • this* 는 다음과 같은 특징을 갖는다.

    • this 는 우변 값으로 간주되므로, this 의 주소를 얻는다든지 this 에 대입한다는 것은 불가능하다.

    • 대부분 this 의 사용은 암시적이다.

16.2.11 멤버 접근

  • 포인터 변수는 -> 를 통해 멤버(변수, 함수) 에 접근할 수 있고,

  • 참조 변수는 . 를 통해 멤버에 접근할 수 있다.

16.2.12 static 멤버

  • 클래스의 일부이면서, 해당 클래스 개체가 아닌 변수를 static 멤버 라고 부른다.

  • 통상적인 비 static 멤버처럼 개체당 하나씩 사본이 있는 것이 아니라,

  • static 멤버는 해당 클래스에 정확히 하나의 사본이 존재한다.

  • 마찬가지로 클래스 멤버 접근을 필요로 하는 함수지만, 특정 개체에 대해 호출될 필요가 없는 함수는 static 멤버 함수라고 부른다.

16.2.13 멤버 타입

  • 타입과 타입 별칭은 클래스의 멤버가 될 수 있다.

template<typename T>
class Tree{
    using value_type = T;
    enum Policy {rb, splay, treeps};
    class Node {
        Node* right;
        Node* left;
        value_type value;
    public : 
        void f(Tree*);
    };
    Node* top;
public : 
    void g(Node*);
    // ...
}

16.3 구체 클래스

  • 사용자가 구체 타입을 정의할 수 있는 타입을 구체 타입(concrete type), 구체 클래스(concrete class) 라고 부른다. -> 이는 추상 클래스, 인터페이스와 반대되는 개념이다.

  • 구체 클래스는 다음과 같은 특징을 가지고 있다. -> 아래와 같은 특징 덕분에 구체 클래스는 쉬운 개념이 되었고, 컴파일러는 필요한 최적의 코드를 쉽게 생성해 줄 수 있게 되었다.

    • 개체를 스택, 정적 할당 메모리, 다른 개체 내부에 둘 수 있다.

    • 개체를 복사하거나 이동할 수 있다.

    • 이름을 가진 개체를 직접적으로 참조할 수 있다.

  • 성능이 중요한 타입에서는 구체 클래스를 우선 사용하기를 권장한다. -> 컴파일러가 최적의 코드를 쉽게 생성해줄 수 있기에 성능이 좋다.

이렇듯 사용자 정의 타입(클래스, 구조체) 의 정의와 효율적인 사용을 적극적으로 지원하자는 것이 초창지 C++ 의 명확한 목표였다!

-> 늘 그렇듯 평범한 것이 복잡하고 수준 높은 것보다 훨씬 중요하다!

  • 이런 관점에서 더 나은 Date 클래스를 만들어보자

namespace Chrono {
    enum class Month { jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
    class Date {
        public: // public interface:
            class Bad_date { }; // exception class
            explicit Date(int dd ={}, Month mm ={}, int yy ={})
        // 변경하지 않는 함수로 Date 를 조사한다. 
            int day() const;
            Month month() const;
            int year() const;
            string string_rep() const; // string representation
            void char_rep(char s[], in max) const; // C-style string representation
        // Date 를 변경하기 위한 (변경) 함수
            Date& add_year(int n); // add n years
            Date& add_month(int n); // add n months
            Date& add_day(int n); // add n days
        private:
            bool is_valid(); // check if this Date represents a date
            int d, m, y; // representation
    };
    bool is_date(int d, Month m, int y); // true for valid date
    bool is_leapyear(int y); // true if y is a leap year
    
    bool operator==(const Date& a, const Date& b);
    bool operator!=(const Date& a, const Date& b);
    const Date& default_date(); // the default date
    ostream& operator<<(ostream& os, const Date& d); // print d to os
    istream& operator>>(istream& is, Date& d); // read Date from is into d
} // Chrono
  • 다음은 Date 가 어떻게 사용되는지 보여주는 예제이다.

    • 열거형 클래스의 사용을 통해 명시적으로 값을 표현해주었다는 것을 주의깊게 보자

void f(Date& d)
{
    Date lvb_day {16,Month::dec,d.year()};
    if (d.day()==29 && d.month()==Month::feb) {
        // ...
    }
    
    if (midnight()) d.add_day(1);
    
    cout << "day after:" << d+1 << '\n';
    
    Date dd; // initialized to the default date
    cin>>dd;
    if (dd==d) cout << "Hurray!\n";
}
Previous3부 : 추상화 메커니즘Next17. 생성, 소멸, 복사와 이동

Last updated 1 year ago