•
타입과 인스턴스
타입(type)을 이용해 인스턴스(instance)를 생성할 수 있음.
타입은 추상화된 것이고 인스턴스는 타입을 실체화한 구체적인 실체.
타입과 인스턴스는 일대다(one-to-many) 관계.
•
속성과 행위
속성(attribute)은 인스턴스가 가지는 특징을 의미함.
행위(behavior)는 어떤 인스턴스가 스스로 할 수 있는 작업 또는 연산을 말함.
•
클래스와 객체
C++은 클래스라는 구문을 사용하여 타입(사용자 정의 자료형)을 생성.
이러한 클래스를 기반으로 만든 인스턴스를 객체라고 부름.
•
데이터 멤버
객체의 데이터 멤버는 속성을 표현하기 위한 변수를 의미함.
객체의 행위는 멤버 함수를 사용해서 구현함.
•
3가지 시스템
새로운 자료형(타입)을 만들 때는 클래스를 사용함.
1. 클래스 정의 - 속성과 행위 선언
2. 멤버 함수 정의 - 행위 정의
3. 애플리케이션 - 클래스를 기반으로 객체를 인스턴스화하고 사용
3가지 시스템으로 분리됨.
1. 클래스 정의
1-1. 데이터 멤버 선언 (접근제한자 : private)
1-2. 멤버 함수 선언 (접근제한자 : public)
→ 접근 제한자는 그룹 단위로 붙임.
2. 멤버 함수 정의
ex)
자료형 클래스명::멤버함수명()const{
~
리턴 값
}
3. 애플리케이션으로 활용 (객체 인스턴스화)
ex)
클래스명 객체명;
객체명.멤버함수명(데이터 멤버 값)
→ 클래스와 멤버 함수를 인스턴스화하여 사용
•
Circle 객체 만들고 사용하기
#include<iostream>
using namespace std;
// const - 변수의 값이 바뀌는 것을 막기 위한 한정사. (상수 취급)
// :: - 스코프 기호
// 클래스 정의
class Circle {
private:
double radius;
public:
double getRadius()const;
double getArea()const;
double getPerimeter()const;
void setRadius(double value);
};
// 멤버 함수 정의
double Circle::getRadius()const {
return radius;
}
double Circle::getArea()const {
const double PI = 3.14;
return(PI * radius * radius);
}
double Circle::getPerimeter()const {
const double PI = 3.14;
return(2 * PI * radius);
}
void Circle::setRadius(double value) {
radius = value;
}
// 애플리케이션 (객체 인스턴스화)
int main() {
cout << "Circle 1: " << endl;
Circle circle1; // circl1이라는 객체로 Circle 클래스를 불러와서 인스턴스화 시킴.
circle1.setRadius(10.0);
cout << "Radius: " << circle1.getRadius() << endl;
cout << "Area:" << circle1.getArea() << endl;
cout << "Perimeter: " << circle1.getPerimeter() << endl << endl;
cout << "Circle 2: " << endl;
Circle circle2;
circle2.setRadius(20.0);
cout << "Radius: " << circle2.getRadius() << endl;
cout << "Area: " << circle2.getArea() << endl;
cout << "Perimeter: " << circle2.getPerimeter() << endl;
return 0;
}
C++
복사
•
접근 제한자
접근 제한자 | 같은 클래스에서의 접근 | 서브 클래스에서의 접근 | 모든 곳으로부터의 접근 |
private | 가능 | 불가능 | 불가능 |
protected | 가능 | 가능 | 불가능 |
public | 가능 | 가능 | 가능 |
데이터 멤버에는 일반적으로 private를 적용.
•
멤버 선택자
객체의 이름과 멤버 함수 사이에 점(.)을 찍어 사용함.
이 연산자를 사용하면 어떤 객체가 갖고 있는 어떤 함수를 실행할 수 있음.
•
생성자와 소멸자
객체가 데이터 멤버를 갖고 어떤 작업을 하려면, 객체를 만든 뒤 데이터 멤버를 초기화하는 작업이 필요함.
객체는 생성자(constructor)라고 부르는 특별한 멤버 함수가 호출될 때 생성됨. 따라서 생성자 내부에서 초기화를 하면 편리.
객체가 더 이상 필요가 없어지는 경우, 객체가 차지하고 있는 메모리를 비워줘야 함(메모리 재활용).
이때는 소멸자(destructor)라고 부르는 특별한 멤버 함수가 호출되어 소멸자 내부에서 객체를 정리하는 작업을 함.
•
생성자
1.
리턴 값이 없음.
2.
이름이 클래스의 이름과 같음.
3.
매개변수가 있는 생성자, 기본 생성자, 복사 생성자 3가지로 구분됨.
•
소멸자
1.
소멸자의 이름은 클래스 이름 앞에 물결 기호(~)가 붙은 형태
2.
소멸자는 리턴 값을 가질 수 없음
•
필수 멤버 함수
그룹 1 : 매개변수가 있는 생성자 / 기본 생성자
그룹 2 : 복사 생성자
그룹 3 : 소멸자
그룹 1은 둘 중 하나의 생성자라도 있어야 함.
둘 다 만들지 않으면, 시스템은 합성 기본 생성자를 생성하여 데이터 멤버를 쓰레기 값으로 초기화함.
그룹 2도 동일.
만들지 않으면, 합성 복사 생성자를 생성.
그룹 3도 동일.
만들지 않으면, 합성 소멸자를 생성.
•
Circle 클래스 완성
#include<iostream>
using namespace std;
// const : 변수의 값이 바뀌는 것을 막기 위한 한정사. (상수 취급)
// 클래스 정의
class Circle {
private:
double radius;
public:
Circle(double radius); // 매개변수 생성자
Circle(); // 기본 생성자
~Circle(); // 소멸자
Circle(const Circle& circle); // 복사 생성자
double getRadius()const;
double getArea()const;
double getPerimeter()const;
void setRadius(double value);
};
// 매개변수 생성자 정의
Circle::Circle(double rds) : radius(rds) {
cout << "The parameter constructor was called. " << endl;
}
// 기본 생성자 정의
Circle::Circle() : radius(0.0) {
cout << "The default constructor was called. " << endl;
}
// 복사 생성자 정의
Circle::Circle(const Circle& circle) :radius(circle.radius) {
cout << "The copy constructor was called. " << endl;
}
// 소멸자 정의
Circle::~Circle() {
cout << "The destructor was called for circle with radius: " << endl;
}
// 멤버 함수 정의
void Circle::setRadius(double value) {
radius = value;
}
double Circle::getRadius()const {
return radius;
}
double Circle::getArea()const {
const double PI = 3.14;
return(PI * radius * radius);
}
double Circle::getPerimeter()const {
const double PI = 3.14;
return(2 * PI * radius);
}
// 애플리케이션 (객체 인스턴스화)
int main() {
Circle circle1(5.2);
cout << "Radius: " << circle1.getRadius() << endl;
cout << "Area:" << circle1.getArea() << endl;
cout << "Perimeter: " << circle1.getPerimeter() << endl << endl;
Circle circle2(circle1);
cout << "Radius: " << circle2.getRadius() << endl;
cout << "Area: " << circle2.getArea() << endl;
cout << "Perimeter: " << circle2.getPerimeter() << endl << endl;
Circle circle3;
cout << "Radius: " << circle3.getRadius() << endl;
cout << "Area: " << circle3.getArea() << endl;
cout << "Perimeter: " << circle3.getPerimeter() << endl << endl;
return 0;
}
C++
복사
•
3개의 랜덤한 숫자 클래스 정의하고 만들기
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
// 데이터 멤버 및 멤버 함수 선언
class RandomInteger {
private:
int low;
int high;
int value;
public:
RandomInteger(int low, int high); // 매개변수 생성자
~RandomInteger(); // 소멸자
RandomInteger(const RandomInteger& random) = delete; // 복사 생성자
void print()const; // 멤버 함수
};
// 생성자 정의
RandomInteger::RandomInteger(int lw, int hw) :low(lw), high(hw) {
srand(time(0));
int temp = rand();
value = temp % (high - low + 1) + low; // 값 범위 지정
}
// 소멸자 정의
RandomInteger::~RandomInteger() {
}
// 멤버 함수
void RandomInteger::print()const {
cout << value << endl;
}
// 애플리케이션
int main() {
RandomInteger r1(100, 200);
cout << "Random number between 100 and 200: ";
r1.print();
RandomInteger r2(400, 600);
cout << "Random number between 400 and 600: ";
r2.print();
RandomInteger r3(1500, 2000);
cout << "Random number between 1500 and 2000: ";
r3.print();
return 0;
}
C++
복사
•
인스턴스 멤버 함수 선택자
어떻게 어떤 객체가 함수를 사용하고 있을 때 잠그고, 모두 사용한 뒤에 다른 객체가 사용할 수 있도록 잠금을 해제할 수 있는 것일까?
→ 락킹과 언락킹을 사용
이를 위해서 멤버 함수에 this 포인터(객체의 주소를 나타내는 변수)를 지정하는 방법을 사용함.
모든 멤버 함수에는 이와 같은 this 포인터가 숨겨져 있음.
(이건 몇 번을 봐도 이해가 안 된다... 코드 이해는 되는데 왜 쓰는지를 이해 못 함)
•
클래스 불변 속성
"객체를 생성하는 인스턴스 멤버 함수 (매개변수가 있는 생성자)" 또는 "데이터 멤버의 값을 변경하는 설정자 멤버 함수"를 사용해서 클래스의 불변 속성을 적용.
#include<iostream>
#include<cassert>
using namespace std;
class Rectangle {
private:
double length;
double height;
public:
Rectangle(double length, double height);
Rectangle(const Rectangle& rect);
~Rectangle();
void print()const;
double getArea()const;
double getPerimeter()const;
};
Rectangle::Rectangle(double len, double hgt) :length(len), height(hgt) {
if ((length <= 0.0) || (height <= 0.0)) {
cout << "No rectangle can be made!" << endl;
assert(false); // 에러검출용 코드. false가 들어오면 assert error!
}
}
Rectangle::Rectangle(const Rectangle& rect) :length(rect.length), height(rect.height) {
}
Rectangle::~Rectangle() {
}
void Rectangle::print()const {
cout << "A rectangle of " << length << " by " << height << endl;
}
double Rectangle::getArea()const {
return(length * height);
}
double Rectangle::getPerimeter()const {
return(2 * (length + height));
}
int main() {
Rectangle rect1(3.0, 4.2);
Rectangle rect2(5.1, 10.2);
Rectangle rect3(rect2);
cout << "Rectangle 1: ";
rect1.print();
cout << "Area: " << rect1.getArea() << endl;
cout << "Perimeter: " << rect1.getPerimeter() << endl << endl;
cout << "Rectangle 2: ";
rect2.print();
cout << "Area: " << rect2.getArea() << endl;
cout << "Perimeter: " << rect2.getPerimeter() << endl << endl;
cout << "Rectangle 3: ";
rect3.print();
cout << "Area: " << rect3.getArea() << endl;
cout << "Perimeter: " << rect3.getPerimeter() << endl << endl;
return 0;
}
C++
복사
•
정적 데이터 멤버
정적 데이터 멤버는 클래스 정의에서 선언해야 하고 static이라는 키워드를 붙임.
•
정적 데이터 멤버 초기화
정적 데이터 멤버는 클래스 정의 후에 초기화해야 하며, 따라서 프로그램의 전역 영역에서 초기화함.
값을 초기화할 때는 클래스 이름과 클래스 스코프 연산자(::)를 추가해서 클래스에 속한다는 것을 나타내야 하며, static을 추가하면 안 됨.
•
정적 멤버 함수
정적 멤버 함수도 static 키워드 붙여서 선언 후 인스턴스 멤버 함수처럼 클래스 외부에서 정의.
인스턴스 또는 클래스를 통해서 호출할 수 있음.
#include<iostream>
using namespace std;
class Rectangle { // 클래스 정의
private: // 데이터 멤버 선언
double length;
double height;
static int count; // 정적 데이터 멤버
public: // 멤버 함수 선언
Rectangle(double length, double height); // 매개변수 생성자
Rectangle(); // 일반 생성자
~Rectangle(); // 소멸자
Rectangle(const Rectangle& rect); // 복사 생성자
static int getCount(); // 정적 멤버 함수
};
// 정적 데이터 멤버 초기화
int Rectangle::count = 0;
// 매개변수 생성자 정의
Rectangle::Rectangle(double len, double hgt) :length(len), height(hgt) {
count++;
}
// 일반 생성자 정의
Rectangle::Rectangle() : length(0.0), height(0.0) {
count++;
}
// 복사 생성자 정의
Rectangle::Rectangle(const Rectangle& rect) : length(rect.length), height(rect.height) {
count++;
}
// 소멸자 정의 -> 정적 데이터 멤버 후위감소 시킴
Rectangle::~Rectangle() {
count--;
}
// 정적 멤버 함수 정의
int Rectangle::getCount() {
return count;
}
// 애플리케이션 -> 객체 인스턴스화
int main() {
{
Rectangle rect1(3.2, 1.2); // 0++
Rectangle rect2(1.5, 2.1); // -> 1++
Rectangle rect3; // -> 2++
Rectangle rect4(rect1); // -> 3++
Rectangle rect5(rect2); // -> 4++ -> 5
cout << "Count of objects: " << rect5.getCount() << endl;
}
cout << "Count of objects: " << Rectangle::getCount() << endl;
return 0;
}
C++
복사
•
은행 계좌 클래스
#include<iostream>
#include<cassert>
using namespace std;
class Account {
private:
long accNumber;
double balance;
static int base; // 정적 데이터 멤버
public:
Account(double bal); // 매개변수 생성자
~Account(); // 소멸자
void checkBalance()const; // 잔액 확인 멤버 함수
void deposit(double amount); // 보증금 멤버 함수
void withdraw(double amount); // 출금 멤버 함수
};
int Account::base = 0;
Account::Account(double bal) :balance(bal) {
if (bal < 0.0) {
cout << "잔액이 맞지 않습니다. 프로그램을 종료합니다.";
assert(false); // false 뜨면 assert error
}
base++;
accNumber = 100000 + base;
cout << "계좌 " << accNumber << " 이(가) 열렸습니다." << endl;
cout << "잔액 $" << balance << endl << endl;
}
Account::~Account() {
cout << "계좌 #: " << accNumber << " 이(가) 닫혔습니다." << endl;
cout << "$" << balance << " 이(가) 고객에게 송금되었습니다." << endl << endl;
}
void Account::checkBalance()const {
cout << "계좌 #: " << accNumber << endl;
cout << "거래: 잔액 확인" << endl;
cout << "잔액: $" << balance << endl << endl;
}
void Account::deposit(double amount) {
if (amount > 0.0) {
balance += amount;
cout << "계좌 #: " << accNumber << endl;
cout << "거래: 보증금 $" << amount << endl;
cout << "새로운 잔액: $" << balance << endl << endl;
}
else {
cout << "거래 실패." << endl;
}
}
void Account::withdraw(double amount) {
if (amount > balance) {
amount = balance;
}
balance -= amount;
cout << "계좌 #: " << accNumber << endl;
cout << "거래: 출금 $: " << amount << endl;
cout << "새로운 잔액: $" << balance << endl << endl;
}
int main() {
// 3개의 계좌 생성
Account acc1(2000);
Account acc2(5000);
Account acc3(1000);
// 거래
acc1.deposit(150);
acc2.checkBalance();
acc1.checkBalance();
acc3.withdraw(800);
acc1.withdraw(1000);
acc2.deposit(120);
return 0;
}
C++
복사