2014-15 intermediate c++ study #6

68
2014-15 INTERMEDIATE C++ STUDY #6 옥찬호

Upload: -

Post on 23-Jun-2015

1.241 views

Category:

Technology


1 download

DESCRIPTION

2014-15 Intermediate C++ Study #6

TRANSCRIPT

Page 1: 2014-15 Intermediate C++ Study #6

2014-15 INTERMEDIATEC++ STUDY #6

옥찬호

Page 2: 2014-15 Intermediate C++ Study #6

스프레드시트 실습

Page 3: 2014-15 Intermediate C++ Study #6

스프레드시트

Page 4: 2014-15 Intermediate C++ Study #6

스프레드시트

SpreadsheetCell

Spreadsheet SpreadsheetApplication

Page 5: 2014-15 Intermediate C++ Study #6

스프레드시트

SpreadsheetCell

Spreadsheet SpreadsheetApplication

이번 시간에는 SpreadsheetCell 클래스에 집중,Spreadsheet와 SpreadsheetApplication 클래스는 다음 시간에 작성.

Page 6: 2014-15 Intermediate C++ Study #6

클래스 만들기클래스의 정의, 메서드의 정의, 객체의 이용

Page 7: 2014-15 Intermediate C++ Study #6

클래스의 정의

클래스 정의는 class로 시작하며 뒤에 이름이 옴!

세미콜론 ;으로 끝나야 함.

Page 8: 2014-15 Intermediate C++ Study #6

클래스의 정의

클래스가 지원하는 메서드

클래스의 데이터 멤버 선언

Page 9: 2014-15 Intermediate C++ Study #6

클래스의 정의

class SpreadsheetCell

Page 10: 2014-15 Intermediate C++ Study #6

클래스의 정의

class SpreadsheetCell

SpreadsheetCell 인스턴스1

SpreadsheetCell 인스턴스2

SpreadsheetCell 인스턴스3

Page 11: 2014-15 Intermediate C++ Study #6

클래스의 정의

class SpreadsheetCell

SpreadsheetCell 인스턴스1

SpreadsheetCell 인스턴스2

SpreadsheetCell 인스턴스3

mValue

mValue

mValue≠

Page 12: 2014-15 Intermediate C++ Study #6

클래스의 정의

클래스는 개념을 정의하고 객체는 실제 데이터 비트를 담는다.따라서 각 개체는 서로 다른 mValue 변숫값을 가진다.그러나 메서드의 구현 내용은 모든 객체가 공유한다.

class SpreadsheetCell

SpreadsheetCell 인스턴스1

SpreadsheetCell 인스턴스2

SpreadsheetCell 인스턴스3

mValue

mValue

mValue

void setValue(double inValue);double getValue() const;

void setValue(double inValue);double getValue() const;

void setValue(double inValue);double getValue() const;

≠≠

==

Page 13: 2014-15 Intermediate C++ Study #6

클래스의 정의

접근 식별자 : public, protected, private

Page 14: 2014-15 Intermediate C++ Study #6

클래스의 정의

클래스의 디폴트 접근자는 private!

Page 15: 2014-15 Intermediate C++ Study #6

클래스의 정의

접근자 의미 활용 예

public객체의 public 메서드 또는 public 멤버 변수는

다른 코드에서 제한 없이 호출하거나 읽고 쓸 수 있다.

사용자 측에서 이용하도록 공개하고 싶은메서드나 private 또는 protected

멤버 변수에 대한 외부 접근 메서드에적용한다.

protected

같은 클래스 안에서만 protected 메서드나멤버 변수를 호출하거나 읽고 쓸 수 있다.

그 클래스의 서브클래스에서도 protected 메서드나멤버 변수에 자유롭게 접근 할 수 있다.

사용자에게는 노출하지 않고내부적으로 이용하기 위한 편의 메서드와

데이터 멤버들에 적용한다.

privateprivate 메서드나 멤버 변수는 해당 클래스 안에서만

접근 할 수 있고 그 클래스의 서브클래스에서도접근이 불허된다.

서브클래스에서의 접근을 막고 싶은항목들에 적용한다.

Page 16: 2014-15 Intermediate C++ Study #6

메서드의 정의

::을 스코프 지정 연산자(Scope Resolution Operator)라고 한다.setValue() 메서드가 SpreadsheetCell 클래스에 속한 것임을 알려준다.

Page 17: 2014-15 Intermediate C++ Study #6

메서드의 정의

setValue() 메서드 안에서 mValue 멤버에 접근해 값을 바꿀 수 있다.서로 다른 두 객체에서 호출된다면 같은 라인의 코드이지만 서로 다른 mValue를 바꾸게 된다.

SpreadsheetCell 인스턴스1

mValue

SpreadsheetCell 인스턴스2

mValue

Page 18: 2014-15 Intermediate C++ Study #6

메서드의 정의

스프레드시트에서는,

0.123 안녕하세요!

숫자뿐만 아니라,텍스트도 표현할 수 있다.

Page 19: 2014-15 Intermediate C++ Study #6

메서드의 정의

텍스트를 위한 Getter/Setter

숫자, 텍스트 상호 변환 함수

텍스트를 저장할 변수

Page 20: 2014-15 Intermediate C++ Study #6

메서드의 정의

Page 21: 2014-15 Intermediate C++ Study #6

메서드의 정의

Page 22: 2014-15 Intermediate C++ Study #6

메서드의 정의

메서드에는 호출된 객체에 접근할 수 있는 숨겨진 파라미터를 넘겨받는다.이 파라미터를 this 포인터라고 하며 이 포인터를 통해 데이터 멤버에도 접근하거나메서드를 호출할 수 있는 것은 물론 다른 메서드의 파라미터로서 전달할 수도 있다.

Page 23: 2014-15 Intermediate C++ Study #6

메서드의 정의

SpreadsheetCell 클래스의 멤버 변수 이름을 mValue에서 value로 바꾸고,setValue() 메서드의 파라미터 이름도 inValue에서 value로 바꿨다고 하자.

어느 value가 클래스 멤버이며, 어느 value가 메서드의 파라미터인가?

Page 24: 2014-15 Intermediate C++ Study #6

메서드의 정의

this 포인터를 이용하면 명확하게 구분이 된다.

Page 25: 2014-15 Intermediate C++ Study #6

메서드의 정의

this 포인터를 다른 함수나 다른 클래스의 메서드를 호출할 때파라미터로 활용할 수도 있다.

Page 26: 2014-15 Intermediate C++ Study #6

객체의 이용

클래스는 건축에서의 청사진과 같다.청사진은 건물이 어떤 모양을 가져야 하는지 규정하지만 실제 건물은 아니다.

class SpreadsheetCell

Page 27: 2014-15 Intermediate C++ Study #6

객체의 이용

청사진으로부터 같은 모양의 여러 건물을 지을 수 있듯이,SpreadsheetCell 클래스 정의로부터 여러 개의 SpreadsheetCell의 객체를 만들 수 있다.

스택에 생성되는 객체 힙에 생성되는 객체

Page 28: 2014-15 Intermediate C++ Study #6

객체의 이용

myCell.setValue(6); 사이에 있는 .은 도트(Dot) 연산자라고 한다.객체를 대상으로 메서드를 호출할 때 도트 연산자를 이용한다.

Page 29: 2014-15 Intermediate C++ Study #6

객체의 이용

힙에 객체를 생성했을 때는 화살표 연산자 ->를 이용해 객체의 메서드와 멤버에 접근한다.

Page 30: 2014-15 Intermediate C++ Study #6

객체의 이용

화살표 연산자는 역참조 연산자(*)와 멤버 / 메서드 접근을 위한 도트 연산자(.)를 합한 것이다.

Page 31: 2014-15 Intermediate C++ Study #6

객체의 이용

스마트 포인터를 이용하면 따로 메모리에서 객체를 해제할 필요가 없다.참조하는 곳이 없으면 자동으로 메모리에서 해제된다.

Page 32: 2014-15 Intermediate C++ Study #6

객체의 라이프 사이클객체의 생성, 객체의 소멸, 객체의 대입

Page 33: 2014-15 Intermediate C++ Study #6

객체의 생성

객체는 스택 변수로 선언하거나 new 또는 new[] 연산자를 호출할 때 생성된다.객체가 될 때는 내부에 포함된 객체들도 함께 생성된다.

Page 34: 2014-15 Intermediate C++ Study #6

객체의 생성

변수를 선언할 때 초깃값을 함께 주면 편리하게 사용할 수 있다.마찬가지로, 객체를 생성할 때도 초깃값을 줄 수 있다. → 생성자(Constructor)

변수

생성자

클래스

Page 35: 2014-15 Intermediate C++ Study #6

객체의 생성

생성자는 문법적으로 볼 때 클래스와 이름이 같은 메서드이다.단, 생성자는 리턴값을 가지지 않으며, 파라미터가 있을 수도 있고 없을 수도 있다.

파라미터가 없는 생성자를 디폴트 생성자(Default Constructor)라고 부른다.

Page 36: 2014-15 Intermediate C++ Study #6

객체의 생성

스택 객체에 대해서 생성자를 올바로 호출하는 방법은변수 선언에 직접 생성자 파라미터를 넣는 방법 뿐이다.

생성자를 메서드로 직접 호출할 수 없다.

생성자를 나중에 호출할 수도 없다.

Page 37: 2014-15 Intermediate C++ Study #6

객체의 생성

힙에 동적으로 객체를 생성할 때는 스택 객체와는 달리SpreadsheetCell 객체의 포인터 변수를 선언할 때 바로 호출하지 않는다.

대신 new 연산자를 이용해서 실제로 객체를 생성하는 시점에생성자 파라미터를 클래스명에 전달하면서 생성자를 호출한다.

포인터 변수를 선언할 때는 nullptr로 초기화하는 것이 바람직하다.

new를 이용해 생성한 객체는 delete를 이용해서 해제해 주어야 한다.

Page 38: 2014-15 Intermediate C++ Study #6

객체의 생성

C++에서는 파라미터의 구성(개수, 타입)이 다르면 같은 이름의 함수(생성자)를 허용한다.함수 호출 시 어떤 함수가 이용될지는 컴파일러가 호출에 사용된 파라미터 구성을

각 함수와 비교해서 결정하게 된다.이러한 메커니즘을 오버로딩(Overloading)이라고 한다.

Page 39: 2014-15 Intermediate C++ Study #6

객체의 생성

Page 40: 2014-15 Intermediate C++ Study #6

객체의 생성

객체의 배열은 두 가지 단계로 생성될 수 있다.모든 객체에 대해 연속된 메모리를 확보한 다음, 각 객체의 디폴트 생성자를 호출한다.C++에서는 디폴트 생성자가 없는 클래스에 대해서는 객체 배열을 생성할 수가 없다.

2연속된 메모리 확보

SpreadsheetCell() SpreadsheetCell() SpreadsheetCell()

각 객체의 디폴트 생성자 호출1

Page 41: 2014-15 Intermediate C++ Study #6

객체의 생성

Page 42: 2014-15 Intermediate C++ Study #6

객체의 생성

컴파일러는 함수명이 myCell이고 리턴 타입이 SpreadsheetCell인 함수 선언으로 착각한다.다음 라인에서는 함수 이름에 대해 객체처럼 도트 연산자를 사용했기 때문에 오류가 발생한다.

그런데 new 연산자로 힙에 객체를 생성할 때는 디폴트 생성자를 함수 호출 형태로 사용해야 한다.

Page 43: 2014-15 Intermediate C++ Study #6

객체의 생성

정의된 생성자가 하나도 없을 때 컴파일러가 자동으로 디폴트 생성자를 만들어 준다.컴파일러가 생성한 디폴트 생성자는 클래스 안에 속한 멤버들에 대해서도 디폴트 생성자를 호출한다.

단 int, double과 같은 기본 타입들은 생성자 호출이 없다.

Page 44: 2014-15 Intermediate C++ Study #6

객체의 생성

C++03에서는 명시적으로 파라미터가 존재하는 생성자를 사용해야 할 때파라미터가 없는 디폴트 생성자도 무조건 정의해 주어야 한다.

Page 45: 2014-15 Intermediate C++ Study #6

객체의 생성

C++11 표준에서는 명시적인 디폴트 생성자(Explicitly Defaulted Constructor)를 지원한다.이것을 사용하면 구현부 없이도 디폴트 생성자를 간편하게 선언할 수 있다.

C++11에서는 명시적으로 삭제된 생성자(Explicitly Deleted Constructor)라는 개념도 지원한다.이 기능을 사용하면 컴파일러가 자동으로 생성하는 디폴트 생성자까지 포함하여

생성자가 전혀 정의되지 않은 클래스를 만들 수 있다.

명시적인 디폴트 생성자 명시적으로 삭제된 생성자

Page 46: 2014-15 Intermediate C++ Study #6

객체의 생성

C++은 생성자 초기화 리스트(Constructor Initializer)라 부르는데이터 멤버 초기화 방법을 제공한다.

리스트는 콜론으로 시작해 각 항목이 쉼표로 나뉜다.각 항목은 데이터 멤버를 함수 호출 형태로 괄호 사이에 초깃값을 받는다.

Page 47: 2014-15 Intermediate C++ Study #6

객체의 생성

C++에서 객체를 생성할 때는 생성자를 호출하기 전에모든 데이터 멤버들이 먼저 생성되어 메모리에 할당된 상태여야 한다.

이 때 객체 타입인 데이터 멤버는 생성자가 호출되고기본 타입들은 그 데이터가 할당된 메모리에 남아있는 임의의 값을 가지게 된다.

mValue = ?mString = “”

mValue = 0mString = “”

Page 48: 2014-15 Intermediate C++ Study #6

객체의 생성

생성자 초기화 리스트는 이러한 과정에서의 멤버에 대한생성자 호출과 기본 타입 데이터의 초깃값을 선택할 수 있게 해준다.

어차피 실행된 과정을 이용하는 것이기 때문에나중에 생성자 바디에서 코드를 통해 초기화하는 것보다 훨씬 효율적이다.

Page 49: 2014-15 Intermediate C++ Study #6

객체의 생성

어떤 데이터 타입들은 생성자 초기화 리스트가 아니면 초기화할 수가 없다.

데이터 타입 설명

const 데이터 멤버const 변수는 그 변수가 생성된 이후에 값을 대입할 수 없다.

이 변수에 대한 초깃값 할당은 반드시 변수의 생성 시점에 되어야 한다.

참조 타입 데이터 멤버 참조 타입은 무엇인가를 참조하지 않은 채로는 존재할 수 없다.

디폴트 생성자가 없는 객체 타입 멤버C++에서는 객체 멤버들을 디폴트 생성자를 이용해 생성한다.

만약 디폴트 생성자가 없는 멤버가 있으면 그 객체를 초기화할 수가 없다.

디폴트 생성자가 없는 슈퍼클래스 이후에 설명할 예정

Page 50: 2014-15 Intermediate C++ Study #6

객체의 생성

생성자 초기화 리스트에서는 초기화 나열 순서에 따라 멤버가 초기화되는 것이 아니라클래스 정의 시점에 멤버들이 등장하는 순서에 따라 초기화된다.

(X)

(O)

Page 51: 2014-15 Intermediate C++ Study #6

객체의 생성

C++에서는 복제 생성자(Copy Constructor)라는 특별한 생성자가 있다.이 생성자는 객체의 복제본을 만들어야 할 때 편리하게 사용된다.

프로그래머가 명시적으로 복제 생성자를 만들지 않으면 컴파일러가 자동으로 만들어준다.

Page 52: 2014-15 Intermediate C++ Study #6

객체의 생성

함수를 호출하면서 파라미터를 넘길 때는 기본적으로 그 값이 복제되어 전달된다.이러한 방식을 값에 의한 전달(Pass-by-Value)이라고 한다.

클래스 객체를 함수나 메서드의 인자로 전달하게 되면 복제 생성자가 호출되어 만들어진다.

Page 53: 2014-15 Intermediate C++ Study #6

객체의 생성

함수/메서드를 호출할 때 파라미터로 넘겨지는 객체의 복제 오버헤드를 피하려면 참조형 타입을 이용하면 된다. 객체가 참조로 전달되면 그 주소 값만 복제되고 내용은 복제되지 않기 때문에 값에 의한 전달보다 더 효율적이다. 또한 복제 오버헤드를 피하기 위한 의도만으로 참조형 타입을 이용한다면 const 키워드를 붙이는 것이 안전하다.

Page 54: 2014-15 Intermediate C++ Study #6

객체의 생성

디폴트 생성자와 마찬가지로, 복제 생성자도 default나 delete 키워드를 이용해컴파일러의 자동생성을 명시적으로 지정하거나 방지할 수 있다.

Page 55: 2014-15 Intermediate C++ Study #6

객체의 생성

C++11에 추가된 initializer_list 생성자는 첫 번째 파라미터로 std::initializer_list<T> 타입을넘겨받으면서 다른 파라미터가 없거나, 디폴트 값이 지정된 파라미터만 가지는 생성자를 말한다.

std::initializer_list<T>를 사용하기 위해서는 <initializer_list>를 인클루드 해야 한다.

Page 56: 2014-15 Intermediate C++ Study #6

객체의 생성

C++11 이전 버전에서는 생성자의 바디나 생성자 초기화 리스트에서만 멤버 초기화를 할 수 있었다.그러나 C++11에서는 멤버 변수의 초기화를 클래스를 정의하는 시점에 바로 할 수 있다.

C++03 C++11

Page 57: 2014-15 Intermediate C++ Study #6

객체의 생성

C++11에 추가된 생성자 위임(Delegating Constructor)은생성자 안에서 같은 클래스의 다른 생성자를 호출하는 것을 말한다.

단, 생성자 바디에서 다른 생성자를 부를 수는 없고 생성자 초기화 리스트를 이용해야 한다.

double 타입 생성자 실행1

string 타입 생성자의 바디 실행2

Page 58: 2014-15 Intermediate C++ Study #6

객체의 생성

생성자를 위임할 때는 재귀적으로 꼬리를 무는 상황은 피해야 한다.이 코드가 어떻게 동작할지는 C++ 표준에 정해진 것이 없으므로 전적으로 컴파일러에 달려있다.

Page 59: 2014-15 Intermediate C++ Study #6

객체의 소멸

객체가 소멸할 때는 두 가지 작업이 발생한다.먼저 객체의 소멸자가 호출되고 난 후, 할당받은 메모리가 반환된다.

소멸자를 정의하지 않으면 컴파일러가 자동으로 생성해준다.자동으로 생성된 소멸자는 클래스 내 멤버들을 돌아가며

재귀적으로 소멸자를 호출하여 객체가 삭제될 수 있도록 한다.

anotherCell 객체는 이 블록이 끝나는 시점에 소멸한다.

myCell은 이 블록이 끝나는 시점에 소멸한다.

Page 60: 2014-15 Intermediate C++ Study #6

객체의 소멸

스택에 생성된 객체는 유효 범위(Scope)에서 벗어날 때 자동으로 삭제된다.즉, 해당 객체가 선언된 함수나 메서드 또는 중괄호 블록을 벗어나는 순간 소멸한다.

또한 스택에 생성된 객체는 생성 순서의 역순으로 삭제된다.

생성 순서 소멸 순서

Page 61: 2014-15 Intermediate C++ Study #6

객체의 소멸

힙에 생성된 객체는 자동으로 소멸되지 않는다.명시적으로 delete 연산자를 호출하면서 객체의 포인터를 인자로 넘겨야만

소멸자가 호출되고 메모리에서 해제된다.

cellPtr1을 삭제한다.

cellPtr2는 delete가 호출되지 않았기 때문에 삭제되지 않는다.

Page 62: 2014-15 Intermediate C++ Study #6

객체의 대입

C++에서는 객체가 생성되면서 값이 초기화될 때만 복제가 일어날 수 있다.이미 메모리를 할당받은 객체에 대해 값이 덮어써지는 상황은 대입이 더 적합한 표현이다.

C++에서는 복제 생성자만이 객체를 복제할 수 있고, 복제 생성자는 객체 생성에만 호출 될 수 있다.C++에서는 객체 간 대입을 지원하는 대입 연산자(Assignment Operator)라는 별도의 방법을 제공한다.

Page 63: 2014-15 Intermediate C++ Study #6

객체의 대입

복제 생성자와 달리 대입 연산자는 SpreadsheetCell의 참조 객체를 리턴한다.그 이유는 대입 연산이 중첩돼서 수행될 수 있기 때문이다.

=

myCell.operator=이 실행되려면 anotherCell.operator=이 반드시 리턴값을 줘야만 한다.

만약 리턴 타입을 SpreadsheetCell&이 아닌SpreadsheetCell로 하면 임시 객체로 인한 복제 오버헤드 발생!

Page 64: 2014-15 Intermediate C++ Study #6

객체의 대입

대입 연산자를 구현할 때 자기 자신을 인자로 하는 경우를 배제해서는 안된다.단, 대입 작업을 그대로 수행하는 것도 문제이다.

대입 연산자가 실행되면 가장 먼저 인자가 자기 자신인지 검사하고만약 그렇다면 복제 작업을 하지 말고 그대로 리턴하게 만들어야 한다.

Page 65: 2014-15 Intermediate C++ Study #6

객체의 대입

컴파일러가 자동으로 생성하는 대입 연산자는 default와 delete 키워드를 이용해명시적으로 사용을 선언할 수도 있고, 배제할 수도 있다.

Page 66: 2014-15 Intermediate C++ Study #6

객체의 대입

어떤 때는 객체가 복제 생성자에 의해 초기화되는 건지대입 연산자가 실행되어 값이 대입되는 건지 모호한 경우가 있다.

기본적으로 변수 선언을 할 때는 복제 생성자가 이용되고대입 연산을 수행할 때는 대입 연산자가 호출된다.

anotherCell은 대입? 복제?복제!

aThirdCell은 대입? 복제?복제!

대입? 복제?대입!

Page 67: 2014-15 Intermediate C++ Study #6

객체의 대입

함수나 메서드에서 객체를 리턴할 때복제가 일어날지 대입이 일어날지 정확히 알 수 없는 때도 있다.

getString() 함수 호출

string 임시 객체 생성 / 복제 생성자 호출

s1의 대입 연산자 호출 / 임시 객체 소멸

1

2

3

getString() 함수 호출1

string 임시 객체 생성 / 복제 생성자 호출2

s2의 복제 생성자 호출 / 임시 객체 소멸3

Page 68: 2014-15 Intermediate C++ Study #6

객체의 대입

컴파일러가 자동으로 생성하는 복제 생성자에서는 멤버들의 복제 생성자를 재귀적으로 호출한다.직접 복제 생성자를 만들 때는 컴파일러가 생성한 복제 생성자와 마찬가지로

생성자 초기화 리스트에서 멤버의 복제 생성자를 호출할 수 있다.이때 만약 멤버 초기화를 빠뜨리면 컴파일러가 빠뜨린 멤버에 대해서 디폴트 생성자를 부른다.

이 디폴트 생성자는 직접 작성한 복제 생성자의 바디가 실행되기 전에 수행된다.이 때문에 생성자 바디가 실행되는 시점에는 이미 모든 멤버들이 초기화된 상태가 된다.

복제 생성자 호출

대입 연산자 호출