수업자료
■ 2월 15일 - 1일차
구조체 메모리 할당
함수 사용시 마다 메모리를 할당 후 추가 되는 구조체
#include <stdio.h>
#include <stdlib.h>
int ix = 0;
typedef struct {
int a;
char* n;
}s;
s* f(s* a, int b, char* c) {
s* n = malloc(sizeof(s) * (++ix));
for (int i = 0; i < ix - 1; i++) {
n[i].a = a[i].a;
n[i].n = malloc(10);
n[i].n = a[i].n;
}
n[ix - 1].a = b;
n[ix - 1].n = malloc(10);
n[ix - 1].n = c;
free(a);
return n;
}
void pr(s* s) {
for (int i = 0; i < ix; i++) {
printf("이름 : %s\n", s[i].n);
printf("나이 : %d\n\n", s[i].a);
}
}
void main() {
s* a = malloc(sizeof(s));
a = f(a, 22, "홍길동");
a = f(a, 33, "백두산");
a = f(a, 11, "안녕");
pr(a);
}
추가 수정 삭제 가능한 구조체
함수 사용시 마다 메모리를 할당 후 추가 되는 구조체
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int number;
int age;
char name[10];
}st;
st z[3] = { {1,20,"홍길동"},{2,30,"백두산"},{3,40,"한라산"}};
st* a = z;
int id = 3;
void pr() {
for (int i = 0; i < id; i++) {
printf("번호 : %d 나이 : %d 이름 : % s\n", a[i].number, a[i].age, a[i].name);
}
}
void sc() {
printf("검색 번호 : ");
for (int i = 0; i < id; i++) {
printf("%d ", a[i].number);
}
printf("몇번 >> ");
int asd;
scanf("%d", &asd);
printf("번호 : %d 나이 : %d 이름 : % s\n",
a[asd - 1].number, a[asd - 1].age, a[asd - 1].name);
}
void del() {
printf("검색 번호 : ");
for (int i = 0; i < id; i++) {
printf("%d ", a[i].number);
}
printf("몇번 >> ");
int asd;
scanf("%d", &asd);
st* ne = malloc(sizeof(st) * (id-1));
int c = 0;
for (int i = 0; i < id; i++) {
if (i == asd - 1) continue;
ne[c].number = c + 1;
ne[c].age = a[i].age;
for (int j = 0; j < 10; j++) {
ne[c].name[j] = a[i].name[j];
}
c++;
}
id--;
a = ne;
}
void ip() {
st* ne = malloc(sizeof(st)*(++id));
for (int i = 0; i < id - 1; i++) {
ne[i].number = i + 1;
ne[i].age = a[i].age;
for (int j = 0; j < 10; j++) {
ne[i].name[j] = a[i].name[j];
}
}
ne[id - 1].number = id;
printf("이름 입력 >> ");
scanf("%s", ne[id - 1].name);
printf("나이 입력 >> ");
scanf("%d", &ne[id - 1].age);
a = ne;
}
void play() {
int num;
while (1) {
printf("====메뉴===\n");
printf("1.입력 2. 출력 3. 검색 4. 삭제 5. 종료\n");
printf("선택 >> ");
scanf("%d", &num);
switch (num) {
case 1:
ip();
break;
case 2:
pr();
break;
case 3:
sc();
break;
case 4:
del();
break;
case 5:
return;
}
printf("\n\n");
}
}
void main() {
play();
}
연결형 리스트
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char* data;
struct st* next;
}st;
void pr(st* a) { // 전체 출력
a = a->next;
while (a != NULL) {
printf("%s\n", a->data);
a = a->next;
}
}
void add(st* a, char* data) { //뒤에 자료 추가
while (a->next != NULL) {
a = a->next;
}
st* ad = malloc(sizeof(st));
a->next = ad;
ad->next = NULL;
ad->data = data;
}
void del(st* a) { // 맨뒤에 삭제
st* b;
while (a->next != NULL) {
b = a;
a = a->next;
}
b->next = NULL;
free(a);
}
void ldel(st* a, char* data) { // 데이터가 맞는 곳 뒤 삭제
while (a->data != data) {
a = a->next;
}
st* b = a->next;
a->next = NULL;
while (b->next != NULL) { // 밑에있는 데이터 닫기
st* c = b;
b = b->next;
free(c);
}
free(b); // 가장 밑에 있는 것 닫기
}
void can(st* a, char* data) { // 자신의 데이터만 삭제 밑에는 연결
st* b;
while (a->data != data) {
b = a;
a = a->next;
}
b->next = a->next;
free(a);
}
int main() {
st* head = malloc(sizeof(st));
st* n1 = malloc(sizeof(st));
head->next = n1;
n1->data = "이순신";
st* n2 = malloc(sizeof(st));
n1->next = n2;
n2->data = "백두산";
st* n3 = malloc(sizeof(st));
n2->next = n3;
n3->data = "한라산";
n3->next = NULL;
add(head, "설악산");
can(head, "백두산");
pr(head);
return 0;
}
■ 2월 16일 - 2일차
c언어의 확장
출력 std::cout << ""'; // printf("");
#include <iostream>
int main(void) {
std::cout << "hello c1";
std::cout << "hello c2" << std::endl;
std::cout << "hello c3\n";
printf("hello c1");
printf("hello c2");
return 0;
}
==========출력==========
hello c1hello c2
hello c3
hello c1hello c2
using namespace std;
string d (스트링 계열 변수 선정)
#include <iostream>
using namespace std;
int main() {
int a = 1;
float b = 3.14;
char c = 'a';
string d = "안녕하세요";
cout << a << b << c << d << endl;
printf("%d %f %c %s", a, b, c, d.c_str());
return 0;
}
==========출력==========
13.14a안녕하세요
1 3.140000 a 안녕하세요
출력에 대한 함수
s[0] 인덱스에 맞는 값 출력
s.at(1) 인덱스에 맞는 값 출력 (s[1] 동일)
s.front() 첫번째 값 출력
s.back() 맨 뒤 값 출력
s.length() 길이 출력
#include <iostream>
int main() {
string sa = "hello";
// 출력
cout << sa[0] << endl;
cout << sa.at(1) << endl;
cout << sa.front() << endl;
cout << sa.back() << endl;
cout << endl;
cout << sa.length() << endl;
return 0;
}
==========출력==========
h
e
h
o
5
입력
cin >> a a에 입력값을 넣으시오
#include <iostream>
using namespace std;
int main() {
int a, b;
cout << "정수를 입력하세요"<< endl;
cin >> a >> b;
cout << "입력한 값은 " << a << ", " << b << "입니다." << endl;
scanf("%d", &a);
scanf("%d", &b);
printf("%d, %d", a, b);
return 0;
}
==========출력==========
정수를 입력하세요
1
2
입력한 값은 1, 2입니다.
2
3
2, 3
문자열 입력 / 한글입력시 2개의 인덱스를 갖음
#include <iostream>
using namespace std;
int main() {
string a;
cout << "문자열을 입력해 주세요" <<endl;
cin >> a;
cout << a[0] <<endl;
cout << a[0] << a[1] << endl;
cout << a << endl;
return 0;
}
==========출력==========
문자열을 입력해 주세요
안녕하세요
안
안녕하세요
==========출력==========
문자열을 입력해 주세요
hellow c
h
he
hellow
자료형 변수 초기화
자료형 변수 = 초기값
자료형 변수(초기값)
#include <iostream>
using namespace std;
int main() {
int a = 10;
cout << a << endl;
int b(20); //초기화에서 만 쓰임
cout << b << endl;
b = 30;
cout << b << endl;
string c("안녕하세요");
cout << c << endl;
return 0;
}
==========출력==========
10
20
30
안녕하세요
레퍼런스(reference) 변수 :: 참조 변수
자료형& 변수이름 = 복사할 변수
int i = 10;
int& re = i;
#include <iostream>
using namespace std;
int main() {
int a = 10;
int* b = &a;
int& r = a;
cout << a << endl;
cout << *b << endl;
cout << r << endl;
a = 20;
cout << a << endl;
cout << *b << endl;
cout << r << endl;
*b = 30;
cout << a << endl;
cout << *b << endl;
cout << r << endl;
r = 1;
cout << a << endl;
cout << *b << endl;
cout << r << endl;
return 0;
}
==========출력==========
10
10
10
20
20
20
30
30
30
1
1
1
레퍼런스 (참조) 할 수 없는 것
상수, 함수, 식
#include <iostream>
using namespace std;
int add() {
int a;
a = 1 + 2;
return a;
}
int main() {
const int a = 1; //상수
int& r = a; //에러
int* p = &a; //에러
int& r2 = add(); //함수 에러
int& r3 = 1+2; //공식 에러
return 0;
}
==========출력==========
에러
int& r = a (a라는 변수의 주소)
r = add() 함수의 값을 a변수에 넣는다.
&r
#include <iostream>
using namespace std;
int add() {
int a;
a = 1 + 2;
return a;
}
int main() {
int a;
int& ra = a;
int* pa = &a;
a = 10;
cout << a << endl;
cout << ra << endl;
ra = a + 16; // *pa = a + 1 동일
cout << a << endl;
cout << ra << endl;
cout << endl;
ra = add();
cout << ra << endl;
cout << &ra << endl;
// &re = a + 1; // 에러 pa = a + 1 동일
return 0;
}
==========출력==========
10
10
26
26
3
00000009B32FF784
레퍼런스 다른변수 주소 및 값 입력
다른 변수의 주소를 넣을 수 없음
#include <iostream>
using namespace std;
int main() {
int v1 = 1;
int v2 = 2;
int& r = v1;
&r = &v2; //에러발생
return 0;
}
다른 변수에 넣으면 그 값으로 변경 주소는 동일
#include <iostream>
using namespace std;
int main() {
int v1 = 1;
int v2 = 2;
int& r = v1;
cout << "v1 : " << v1 << endl;
cout << "v2 : " << v2 << endl;
cout << "r : " << r << endl;
cout << endl;
r = v2;
cout << "v1 : " << v1 << endl;
cout << "v2 : " << v2 << endl;
cout << "r : " << r << endl;
cout << endl;
r = 3;
cout << "v1 : " << v1 << endl;
cout << "v2 : " << v2 << endl;
cout << "r : " << r << endl;
cout << "v1주소 : " << &v1 << endl;
cout << "v2주소 : " << &v2 << endl;
cout << "r 주소 : " << &r << endl;
return 0;
}
==========출력==========
v1 : 1
v2 : 2
r : 1
v1 : 2
v2 : 2
r : 2
v1 : 3
v2 : 2
r : 3
v1주소 : 00000043A08FF614
v2주소 : 00000043A08FF634
r 주소 : 00000043A08FF614
레퍼런스를 함수에서 사용
#include <iostream>
using namespace std;
void change(int& r, int a) {
r = a;
}
int main() {
int n = 5;
cout << n << "\n";
change(n, 2);
cout << n << endl;
return 0;
}
==========출력==========
5
2
레퍼런스 함수 선언과 구성
void change(int&); // 선언
void change(int& r) { //정의
r = 10;
}
레퍼런스 2개를 받아 값을 변화시키는 함수
#include <iostream>
using namespace std;
void sw(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int a = 1, b = 3;
cout << "a : " << a << " &a : " << &a << endl;
cout << "b : " << b << " &b : " << &b << endl;
sw(a, b);
cout << "a : " << a << " &a : " << &a << endl;
cout << "b : " << b << " &b : " << &b << endl;
return 0;
}
==========출력==========
a : 1 &a : 000000D9BF8FFB04
b : 3 &b : 000000D9BF8FFB24
a : 3 &a : 000000D9BF8FFB04
b : 1 &b : 000000D9BF8FFB24
for문
기본
for (초기조건; 반복조건; 증가 / 감소) {
반복내용
}
for (변수(원소) : 반복 가능한 객체) {
반복 내용;
}#include <iostream> using namespace std; int main() { int arr[10] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; for (int i = 0; i < 10; i++) { cout << arr[i] << " "; } cout << endl; // 배열에 있는 값에 대해서 받음 for (int i : arr) { cout << i << " "; } cout << endl; for (int j : arr) { cout << j << " "; ++j; } cout << endl; for (int& k : arr) { ++k; cout << k << " "; } cout << endl; return 0; } ==========출력========== 10 20 30 40 50 60 70 80 90 100 10 20 30 40 50 60 70 80 90 100 10 20 30 40 50 60 70 80 90 100 11 21 31 41 51 61 71 81 91 101
함수
오버로드
#include <iostream> using namespace std; void swap(int& a, int& b) { int temp = a; a = b; b = temp; } void swap(double& a, double& b) { double temp = a; a = b; b = temp; } void swap(char& a, char& b, char& c) { char temp = a; a = b; b = c; c = temp; } void swap(string& a, string& b, string& c) { string temp = a; a = b; b = c; c = temp; } int main() { int a = 1, b = 2; swap(a, b); cout << a << " " << b << endl; double ad = 1.1, bd = 2.2; swap(ad, bd); cout << ad << " " << bd << endl; char ac = 'a', bc = 'b', cc = 'c'; swap(ac, bc, cc); cout << ac << " " << bc << " " << cc << endl; string as = "안녕", bs = "백두산", cs = "한라산"; swap(as, bs, cs); cout << as << " " << bs << " " << cs << endl; return 0; } ==========출력========== 2 1 2.2 1.1 b c a 백두산 한라산 안녕
디폴트 매개변수#include <iostream> using namespace std; // 디폴트 매개변수는 뒤에서 부터 차례대로 지정 void dc1(int a, int b = 0) { cout << a << " " << b << " " << endl; } void dc2(int a, int b, int c = 0) { cout << a << " " << b << " " << c << endl; } int main() { dc1(1); dc1(1, 2); dc2(20, 100); dc2(40, 10, 30); return 0; } ==========출력========== 1 0 1 2 20 100 0 40 10 30
네임 스페이스 만들기
#include <iostream>
using namespace std;
namespace student {
string name[10];
int cs[10];
int ix = 0;
void pr() {
for (int i = 0; i < ix; i++) {
cout << "이름 : " << name[i] << " 반 : " << cs[i] << endl;
}
}
void in(string i1, int i2) {
name[ix] = i1;
cs[ix] = i2;
ix++;
}
void del() {
ix--;
}
void del(string a) {
for (int i = 0; i < ix; i++) {
if (a == name[i]) {
for (int j = i+1; j < ix; j++) {
name[j-1] = name[j];
cs[j - 1] = cs[j];
}
ix--;
break;
}
}
}
}
int main() {
student::in("홍길동", 3);
student::in("백두산", 8);
student::in("한라산", 2);
student::del("백두산");
student::pr();
return 0;
}
■ 2월 22일 - 3일차
스텍
#include <stdio.h>
#include <stdlib.h>
int stack[5];
int top = -1;
void add() {
if (top == 4) {
printf("스택이 가득 참");
}
else {
printf("저장 >> ");
scanf("%d", &stack[++top]);
}
}
void pr() {
if (top == -1) {
printf("자료가 없습니다.");
}
else {
for (int i = 0; i <= top; i++) {
printf("%d ", stack[i]);
}
}
}
void del() {
if (top == -1) {
printf("비어있다.");
}
else {
printf("%d가 삭제 됨", stack[top--]);
}
}
void main() {
printf("\n------------메뉴----------\n");
int cho;
while (1){
printf("\n\n1.삽입 2.삭제 3.데이터 4. 종료\n");
printf("입력 >> ");
scanf("%d", &cho);
switch (cho) {
case 1:
add();
break;
case 2:
del();
break;
case 3:
pr();
break;
case 4:
return 0;
}
}
}
큐
#include <stdio.h>
#include <stdlib.h>
int stack[5];
int s = 0, e = 0;
void add() {
if ((e + 1) % 5 == s) {
printf("큐가 가득 참");
}
else {
printf("자료 >> ");
scanf("%d", &stack[e]);
e = ++e % 5;
}
}
void pr() {
for (int i = s; i != e; i = ++i % 5) {
printf("%d ", stack[i]);
}
}
void del() {
if (s == e) {
printf("큐가 비어있음");
}
else {
s++;
s %= 5;
}
}
void main() {
printf("\n------------메뉴----------\n");
int cho;
while (1){
printf("\n\n1.삽입 2.삭제 3.데이터 4. 종료\n");
printf("입력 >> ");
scanf("%d", &cho);
switch (cho) {
case 1:
add();
break;
case 2:
del();
break;
case 3:
pr();
break;
case 4:
return 0;
}
}
}
기본 변형 (네임스페이스 미리 정의된 변수의 값 변경)
#include <iostream>
#include <iomanip>
using namespace std;
namespace num {
int x = 100;
int y = 222;
void sum(int, int);
}
namespace num2 {
void numx() {
num::x = 50;
}
}
int main() {
cout << num::x <<endl;
cout << num::y << endl;
num::sum(1, 2);
num::sum(1, 5);
cout << endl;
num2::numx;
cout << num::x << endl;
return 0;
}
void num::sum(int a, int b) {
cout << a << " + " << b << " = " << a + b << endl;
}
==========출력==========
100
222
1 + 2 = 3
1 + 5 = 6
100
네임스페이스 중첩
기본
#include <iostream>
using namespace std;
namespace na {
int a = 1;
void sum(int a, int b) {
cout << a + b << endl;
}
namespace nb {
void nbf() {
na::a = 2;
}
}
}
int main() {
cout << na::a << endl;
na::nb::nbf();
cout << na::a << endl;
return 0;
}
==========출력==========
1
2
기본 변형 (nc 추가, a값 변동, b값 변동)
#include <iostream>
using namespace std;
namespace na {
int a = 1;
void sum(int a, int b) {
cout << a + b << endl;
}
namespace nb {
int b = 10;
void nbf() {
na::a = 2;
}
namespace nc {
void ncf() {
na::a = 3;
na::nb::b = 20;
}
}
}
}
int main() {
cout << na::nb::b << endl;
na::nb::nc::ncf();
cout << na::a << endl;
cout << na::nb::b << endl;
return 0;
}
==========출력==========
10
3
20
기본 변형 (using namespace na::nb::nc 선정 함수만 사용으로 발동)
#include <iostream>
using namespace std;
namespace na {
int a = 1;
void sum(int a, int b) {
cout << a + b << endl;
}
namespace nb {
int b = 10;
void nbf() {
na::a = 2;
}
namespace nc {
void ncf() {
na::a = 3;
na::nb::b = 20;
}
}
}
}
using namespace na::nb::nc;
int main() {
cout << na::nb::b << endl;
ncf();
cout << na::a << endl;
cout << na::nb::b << endl;
return 0;
}
==========출력==========
10
3
20
객체지향 프로그래밍
객체지향 이전의 프로그래밍 패러다임
프로그래밍 패러다임
프로그램밍 패러다임은 프로그램을 어떤 절차와 구조로 만들것인지에 대한
스타일이나 접근 방법을 나타낸다.
집을 짓는 방법이 여러가지 이듯이 프로그래밍 패러다임도 여러가지가 있으며
복잡도와 필요성에 따라 변화 발전했다.
각 패러다임은 언어가 지원하는 기능, 코드의 구조,
문제 해결, 접근 방식등에 차이가 있으며,
각 패러다임이 무엇이 좋고 나쁜지 보다는 방식이 다른 것임
비구조적 프로그래밍
코드를 구조화 하지 않고 작성하는 방법
첫번째 줄 부터 마지막 줄까지 차례대로 실행되어 코드의 흐름을 이동
어셈블리, 포틀란 등
절차적 프로그래밍
소스 코드를 여러 부분으로 나누어서 활용하는 패러다임으로
프로시저를 이용해 구조화 하는 방식임
프로시저 : 일련의 코드 묶음 보통 함수를 의미
코드의 논리 구조를 모듈화 할 수 있으며
모듈화 하면 같은 기능을 수행하는 코드를 다시 작성하지 않아도 재사용할 수 있음
라이브러리처럼 누군가가 만들어 놓은 기능을 사용하면 프로그램을 더 쉽게 개발하고
구조화 된 코드는 다른사람이 쉽게 읽을 수 있음
기능을 프로시저 단위로 나누어 구현하면
기능을 변경할 때 프로그램의 전체 흐름은 그대로 두고
프로시저를 구현하는 코드만 수정하여 관리 해도 됨
절차적 프로그래밍 한계
코드가 점점 복잡해지고 다양해지면서 프로시저도 대폭늘어가고
거기에 맞춰 프로시저간의 관계도 복잡해 지고 있음.
프로젝트에 참여하는 모든 개발자가
프로그램의 복잡한 논리구조를 정확하게 이해하고 접근해야 한다.
객체지향 프로그래밍
객체지향 프로그래밍 개념
객체라는 논리적인 개념으로 코드를 구성
데이터와 함수를 포함하는 객체를 활용하는 프로그래밍 패러다임으로다양한 객체간의 관계를 소스코드로 구성하여 프로그래밍을 완성함
절차적 프로그래밍은 프로그램이 수행할 기능을 프로시저라는 단위로 쪼개어 문제를 해결한다면
객체지향 프로그래밍은 객체라는 논리적인 단위를 먼저 정의하여 이를 조합해
프로그램이 수행할 기능을 만드는 방법
절차적은 전체 기능을 모두 파악한 후
이를 구현하지 위해 작은 단위로 만드는 것이라면
객체지향은 독립적인 객체를 정의하고 거기에 맞는 기능을 만드는 방식
절차적은 자동차의 모든 기능과 관계를 구성해서 프로그래밍한다면
객체지향은 자동차의 논리적인 단위를 정의 (엔진, 뼈대, 동력장치등)
엔진은 연료에 따라 다양한 가스, 휘발유, 디젤, 전기 엔진으로 변경할 수 있음
클래스 연습
#include <iostream>
using namespace std;
class c1 {int arr[10];int ix;
void ipix(int a) {
if (a >= 0 && a <= 9) { ix = a; }
else { ix = 0; }
}
public:
void apr() { for (int i : arr) { cout << i << " ";} }
void add(int a=0) { for (int& i : arr) {i = a;} }
void iadd(int a, int b) {
ipix(a);
arr[ix] = b;
}
void ipr(int a, int b) {
if (a < 0 || b>9) {
}
else {
for (int i = a; i <= b; i++) {
cout << arr[i] << " ";
}
}
cout << endl;
}
};
int main() {
c1 a;
a.add(0);
a.iadd(3, 10);
a.iadd(2, 22);
a.iadd(1, 17);
a.ipr(1,4);
return 0;
}
생성자와 소멸자
클레스명(){
생성자
}
객체가 초기화 된다.
~클레스명(){
소멸자
}
객체가 할당 받은 메모리를 해제한다.
#include <iostream>
using namespace std;
class ts {
int test;
public:
ts() {
cout << "생성자 호출" << endl;
}
~ts() {
cout << "소멸자 호출" << endl;
}
};
ts global;
int main() {
cout << "main 함수 시작" << endl;
cout << "main 함수 종료" << endl;
return 0;
}
==========출력==========
생성자 호출
main 함수 시작
main 함수 종료
소멸자 호출
#include <iostream>
using namespace std;
class ts {
int test;
public:
ts() {
cout << "생성자 호출" << endl;
}
~ts() {
cout << "소멸자 호출" << endl;
}
};
ts global;
void pr() {
cout << "print 함수 시작" << endl;
//ts local; // 지역객체
cout << "print 함수 끝" << endl;
}
int main() {
cout << "main 함수 시작" << endl;
pr();
cout << "main 함수 종료" << endl;
return 0;
}
==========출력==========
생성자 호출
main 함수 시작
print 함수 시작
print 함수 끝
main 함수 종료
소멸자 호출
==변경== // 지역객체 주석 풀면 시행
생성자 호출
main 함수 시작
print 함수 시작
생성자 호출
print 함수 끝
소멸자 호출
main 함수 종료
소멸자 호출
클래스
생성자를 활용한 초기화
#include <iostream>
#include <string>
using namespace std;
class num {
int a;
int b;
public:
int getA() {
return a;
}
num() : a(0), b(0) {
}
num(int x, int y) : a(x), b(y) {
}
};
int main() {
num a1;
cout << a1.getA() << endl;
num a2 = num(15, 20);
cout << a2.getA() << endl;
}
==========출력==========
0
15
클래스 상속
먼저 만들어진 클래스의 맴버(변수, 메서드)를 물려받아 사용
부모 클래스 : 물려주는(상속하는) 클래스
자식 클래스 : 물려받는(상속받는) 클래스접근 제어 지시자
public : 어디서든 접근이 가능
private : 클래스 내부에 정의된 함수에서만 접근허용
protected : 기본적으로 private이지만 상속관계에 놓여 있을때 허용
class 상속 클래스명 : public 상위클래스
#include <iostream>
using namespace std;
#define Pr(a) cout << a << endl;
class prt {
public:
int pn;
void prtf() {
Pr("부모 클래스");
}
};
class chd : public prt {
public:
int cn;
void chdf() {
Pr("자식 클래스");
}
};
class gchd : public chd {
public:
int gn;
void gchdf() {
Pr("손자 클래스");
}
};
int main() {
prt a; // 부모클래스
a.pn = 50;
Pr(a.pn);
a.prtf();
Pr(' ');
chd b;
b.pn = 52;
Pr(b.pn);
b.prtf();
b.cn = 31;
Pr(b.cn);
b.chdf();
Pr(' ');
gchd c;
c.pn = 48;
Pr(c.pn);
c.prtf();
c.cn = 29;
Pr(c.cn);
c.chdf();
c.gn = 3;
Pr(c.gn);
c.gchdf();
return 0;
}
==========출력==========
50
부모 클래스
52
부모 클래스
31
자식 클래스
48
부모 클래스
29
자식 클래스
3
손자 클래스
■ 2월 23일 - 4일차
■ 영화관 티켓팅 자료
○ Ticket 클래스 제작 1
- 클래스 제작 및 protected 변수 생성자 제작
Ticket을 제작하고 변수로는 title[7]배열 영화제목 저장
seat char 배열 8-6으로 제작하고
생성자를 활용하여 문자 'O' 으로 초기화 하시오
seatShow() 함수를 제작하고 출력
#include <iostream>
using namespace std;
class Ticket {
protected:
string title[7] = {"아바타","어벤져스","겨울왕국","인터스텔라","탑건","스파이더맨","아이언맨"};
char seat[8][6];
public:
Ticket() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 6; j++) {
seat[i][j] = 'O';
}
}
}
void seatShow() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 6; j++) {
cout << i+1<<j+1 << " : " << seat[i][j] << " ";
}
cout << endl;
}
}
};
int main() {
Ticket a = Ticket();
a.seatShow();
return 0;
}
11 : O 12 : O 13 : O 14 : O 15 : O 16 : O
21 : O 22 : O 23 : O 24 : O 25 : O 26 : O
31 : O 32 : O 33 : O 34 : O 35 : O 36 : O
41 : O 42 : O 43 : O 44 : O 45 : O 46 : O
51 : O 52 : O 53 : O 54 : O 55 : O 56 : O
61 : O 62 : O 63 : O 64 : O 65 : O 66 : O
71 : O 72 : O 73 : O 74 : O 75 : O 76 : O
81 : O 82 : O 83 : O 84 : O 85 : O 86 : O
- reserve 멤버 함수 제작
reserve를 실행하면 시트를 보여주고 행열을 넣어주면
11미만 86초과 또는 1의 자리가 6을 넘어가던지 0이면 잘못된 좌석 선택메시지
잘할때 까지 무한 반복
제대로 입력하면 좌석에 X문자 저장 후 시트를 보여주고 종료
void reserve() {
seatShow();
while (1) {
int i = 0;
cout << "예약할 행과 열을 입력 하세요 >> ";
cin >> i;
if (i < 11 || i > 86 || i % 10 > 6 || i % 10 == 0) {
cout << "잘못된 좌석을 선택하였습니다." << endl;
}
else {
seat[i / 10 - 1][i % 10 - 1] = 'X';
seatShow();
break;
}
}
}
- reserveAdd() 멤버함수 제작
숫자를 넣으면 인덱스에 X를 넣어주고 seatReserve에 저장 srindex는 증가
setReserve에 값이 있으면 미실행
seatReserve에 있는 값을 넣어주면 예약된 좌석임을 출력하도록 reserve 함수 변경
int seatReserve[48] ={};
int srindex = 0;
void reserveAdd(int a) {
if (!reserveCheck(a)){
seat[a / 10 - 1][a % 10 - 1] = 'X';
seatReserve[srindex++] = a;
}
}
void reserve() {
seatShow();
while (1) {
int i = 0;
cout << "예약할 행과 열을 입력 하세요 >> ";
cin >> i;
if (i < 11 || i > 86 || i % 10 > 6 || i % 10 == 0) {
cout << "잘못된 좌석을 선택하였습니다." << endl;
}
else if (reserveCheck(b)) {
cout << "예약 된 좌석입니다." << endl;
}
else {
seat[i / 10 - 1][i % 10 - 1] = 'X';
seatReserve[srindex++] = i;
seatShow();
break;
}
}
}
-reserveCheck(int) 좌석 체크하여 bool 형 반환 함수
bool reserveCheck(int a) {
bool b = false;
for (int i : seatReserve) {
if (i == a) {
b = true;
}
}
return b;
}
- 랜덤한 숫자 나오기
srand(time(NULL));
for (int i = 0; i < 10; i++) {
int n = rand()%90;
cout << n << " " << endl;
}
- randomReserve(int) 멤버함수 제작
int 값에 맞게 reserveAdd() 메서드 실행
당연히 이전 예약 되어 있으면 미실행 int에 넣은 값 만큼 예약되기
void randomReserve(int a) {
for (int i = 0; i < a; ) {
int n = rand() % 90;
if (n < 11 || n > 86 || n % 10 > 6 || n % 10 == 0) {
}
else if(!reserveCheck(n)) {
reserveadd(n);
i++;
}
}
}
int main(){
srand(time(NULL));
return 0;
}
- seatReserveCheck() 좌석 예약 체크 출력 함수 제작
void seatReserveCheck() {
for (int i = 0; i < srindex; i++) {
cout << seatReserve[i] << " ";
}
cout << endl;
}
-removeReserve(int) 제작
좌석번호를 받아서 예약된 좌석 삭제 그 이후 배열내용 이동
protected에 제작
void removeReserve(int a) {
for (int i = 0; i < srindex; i++) {
if (seatReserve[i] == a) {
for (int j = i; j < srindex; j++) {
seatReserve[j] = seatReserve[j + 1];
}
}
}
srindex--;
}
-cancelReserve() 제작
현재 예약된 좌석이 출력되고
취소할 좌석 입력
체크 해서 제대로 입력 되었으면
remove 함수 이용 삭제 후 삭제 되었는지 출력
잘못 입력시 예약된 좌석이 아님을 알리고 재입력은 0을 눌러서 함수 재실행
void cancelReserve() {
seatReserveCheck();
cout << endl << "취소할 좌석 번호 입력 >> ";
int s;
cin >> s;
if (reserveCheck(s)) {
cout << s << " 좌석예약이 취소" << endl;
removeReserve(s);
seatReserveCheck();
seat[s / 10 - 1][s % 10 - 1] = 'O';
}
else {
cout << "예약된 좌석이 아닙니다. (재입력은 0) >> ";
cin >> s;
if (!s) cancelReserve();
}
}
-play() 제작
1. 예약석확인
2. 예약
3. 취소
4. 몇명랜덤 예약
5. 현황 확인
6. 종료
void play() {
while (1) {
cout << endl << endl << "==메뉴==" << endl;
cout << "1. 예약석 확인 \n2. 예약 \n3.취소\n4.랜덤예약\n5.현황 확인\n6.종료" << endl;
cout << "입력 >> ";
int a;
cin >> a;
switch (a) {
case 1:
seatReserveCheck();
break;
case 2:
reserve();
break;
case 3:
cancelReserve();
break;
case 4:
cout << "몇명 >> ";
int r;
cin >> r;
randomReserve(r);
break;
case 5:
seatShow();
break;
case 6:
break;
}
if (a == 6) {
break;
}
}
}
■ 3월 8일 - 5일차
클래스의 접근제어 지시자 받는 요령
private 는 자식클래스에서도 변경 불가
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class parent {
private:
int a;
int b;
void inint() {
pr("첫번째 정수를 입력하세요");
cin >> a;
pr("두번째 정수를 입력하세요");
cin >> b;
}
void prpa() {
pr(a << " " << b)
}
};
class child : public parent {
void t() {
this->a = 10; // private 로 되어 있으면 a를쓸수 없음
}
};
protected는 밖에서 변경 불가, 자식은 변경가능
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class parent {
protected:
int a;
public:
int b;
void inint() {
pr("첫번째 정수를 입력하세요");
cin >> a;
pr("두번째 정수를 입력하세요");
cin >> b;
}
void prpa() {
pr(a << " " << b)
}
};
class child : public parent {
void t() {
this->a = 10;
this->b = 20;
}
};
int main() {
child a;
a.a = 22; // protected 로 하면 밖에서 변경 불가
// 그러나 자식 클래스는 변경가능
return 0;
}
public 은 밖에서도 자식클래스도 변경가능
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class parent {
protected:
int a;
public:
int b;
void inint() {
pr("첫번째 정수를 입력하세요");
cin >> a;
pr("두번째 정수를 입력하세요");
cin >> b;
}
void prpa() {
pr(a << " " << b)
}
};
class child : public parent {
void t() {
this->a = 10;
this->b = 20;
}
};
int main() {
child a;
a.b = 22;
return 0;
}
문제
부모클래스 prt 생성
변수 string name은 prt클래스에서만 변경가능
변수 int age는 자식클래스에서 변경가능
변수 float length는 모두 변경가능부모 클래스에 함수 prtin 정의
이름을 입력하세요를 출력하고 입력값을
변수 string name에 저장자식 클래스 ch 생성
자식클래스에 chin 함수 정의
나이를 입력하세요
나이가 1~120일때는 다시입력하세요
while문 및 if문 작성
입력값을 부모클래스 변수 int age에 저장부모클래스에 prtpr 함수 정의
이름 : xxx, 나이 : xx, 키 : xx 출력main에 ch 클래스 a라는 변수로 생성
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class prt {
private:
string name;
protected:
int age;
public:
float length;
void prtin() {
pr("이름을 입력하세요");
cin >> this->name;
}
void prtpr() {
pr("이름 : " << name << ", 나이 : " << age << "키 : " << length)
}
};
class ch : public prt {
public:
void chin() {
while (1)
{
pr("나이를 입력하세요");
int a;
cin >> a;
if ((a > 0) && (a <= 120)) {
age = a;
break;
}
else {
pr("다시 입력해주세요")
}
}
}
};
int main() {
ch a;
a.prtpr();
a.length = 171.2;
a.prtpr();
a.prtin();
a.prtpr();
a.chin();
a.prtpr();
return 0;
}
==========출력==========
이름 : , 나이 : -858993460키 : -1.07374e+08
이름 : , 나이 : -858993460키 : 171.2
이름을 입력하세요
홍길동
이름 : 홍길동, 나이 : -858993460키 : 171.2
나이를 입력하세요
22
이름 : 홍길동, 나이 : 22키 : 171.2
클래스 상속 오버라이딩
오버로딩은 자료형이나 수가 다른 함수를 같은 이름으로 여러번 중복
오버라이딩은 부모에서 정의된 함수를 같은 이름으로 자식클래스에 재정의
오버라이딩시 부모 클래스의 함수는 모두 가려짐
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class prt {
protected:
int a;
int b;
public:
void test() {
a = 1;
b = 2;
pr(a << " " << b);
}
};
class ch : public prt {
public:
void test() {
a = 123;
b = 12;
pr(a << " " << b);
}
};
int main() {
prt a;
a.test();
ch b;
b.test();
return 0;
}
==========출력==========
1 2
123 555
부모 클래스의 함수 사용법
부모클래스명::함수명()
- 자식의 함수안에 넣어서 사용
void test() {
prt::test();
a = 123;
b = 555;
pr(a << " " << b);
}
- 새로운 함수를 자식에 만들어서 부모것 불러들임
void ptest() {
prt::test();
}
- 메인에서 부모 클래스의 함수를 불러들임
b.prt::test();
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class prt {
protected:
int a;
int b;
public:
void test() {
a = 1;
b = 2;
pr(a << " " << b);
}
};
class ch : public prt {
public:
void test() {
a = 123;
b = 555;
pr(a << " " << b);
}
void ptest() {
prt::test();
}
};
int main() {
prt a;
a.test();
ch b;
b.test();
b.ptest();
b.prt::test();
return 0;
}
==========출력==========
1 2
123 555
1 2
1 2
생성자 상속
부모가 생성자를 가지고 있으면 자식이 부모의 생성자를 만족하고 생성해야한다.
즉 부모가 int 형태를 가지고 생성하면 자식도 동일하게 주어야 만들어 줄수 있다.
자식생성자(int 매개변수): 부모클래스명(값){
}
#include <iostream>
using namespace std;
class p {
public:
int a;
p(int a2) {
a = a2;
}
void pr() {
cout << a << endl;
}
};
class p2: public p{
public:
p2(int p2a):p(p2a){
}
};
void main() {
p2 a = p2(7);
a.pr();
}
아이디와 패스워드를 가지고 있는 클래스 만들기
부모는 생성자에 String 형과, int 형을 받아 id에 string을 pw에 int를 받아서 작업
자식이 부모를 상속받아 사용 생성자 만들기
#include <iostream>
using namespace std;
class p {
protected:
string id;
int pw;
public:
p(string a1, int a2) :id(a1), pw(a2) {}
void pr() {
cout << "아이디 : " << id << " pw : ";
for (int i = pw; i > 0; i /= 10) {
cout << "*";}
cout << endl;}
};
class p2 : public p {
public:
p2(string a1, int a2) :p(a1,a2) {}
void pr2(p2 a[], int b) {
for (int i = 0; i < b; i++) {
a[i].pr();
}
}
};
void main() {
p2 a[] = { p2("qwer",1230123),p2("asdfa",123123),p2("qweasd",123) };
a[0].pr2(a, 3);
}
변형
#include <iostream>
#include <string>
using namespace std;
class p {
protected:
string id;
int pw;
public:
p(string a, int b) : id(a), pw(b) {
}
void pr() {
cout << "아이디 : " << id << " pw : ";
for (int i = pw; i > 0; i /= 10) {
cout << "*";
}
cout << endl;
}
};
class c : public p {
private:
string idget() {
return id;
}
public:
c(string a, int b) : p(a, b) {
}
void pr() {
cout << "아이디 : " << id << " pw : ";
for (int i = pw; i > 0; i /= 10) {
if (i < 10) {
cout << pw%10;
break;
}
cout << "*";
}
cout << endl;
}
string pwc(int a) {
if (a == pw) {
return idget();
}
else {
return "x";
}
}
};
class ca {
public:
void pr(c x[], int b) {
for (int i = 0; i < b; i++) {
x[i].pr();
}
}
void idpr(int a, c b[], int c) {
for (int i = 0; i < a; i++) {
if (b[i].pwc(c) != "x") {
cout << b[i].pwc(c);
}
}
}
};
int main() {
c a[] = { c("kim", 12487),c("asdas",28124),c("qwe",121729)};
ca z;
z.idpr(3, a, 28124);
return 0;
}
클래스 다중상속
두개의 클래스를 자식클래스에서 상속가능
자바는 다중상속 불가 인터페이스만 허용예시) 카메라 기능과 전화 기능을 합한 스마트폰
#include <iostream>
using namespace std;
class camera {
protected:
string film;
public:
camera(string a) : film(a) {
}
void photo_shoot(string screen) {
camera::film = screen;
// this->film = screen; 위와 동일
}
void photo_printing() {
cout << this->film << " 출력" << endl;
}
void get() {
cout << film << endl;
}
};
class phone {
protected:
string phone_number;
public:
phone(string b) : phone_number(b) {
}
void button_pressure(string number) {
this->phone_number = number;
}
void mc() {
cout << this->phone_number << " 전화연결" << endl;
}
void get() {
cout << phone_number << endl;
}
};
class smartphone : public camera, public phone {
public:
smartphone(string ca, string cp) : camera(ca), phone(cp) {
}
smartphone() : camera("0"), phone("0") {
}
};
int main() {
smartphone a;
a.photo_shoot("아파트 사진");
a.photo_printing();
a.button_pressure("010-1234-1234");
a.mc();
return 0;
}
다중상속시 발생할수 있는 문제
두 부모 클래스에서 동일한 함수가 중복되어 있을시
어떤것을 호출 해야 하는지 애매해 애러가 생긴다.
a.get(); // 어떤것을 불러들일지 에러 발생
해결방안 (이런문제로 인해 java에서는 사용하지 않음)
// a.get(); // 어떤것을 불러들일지 에러 발생
a.camera::get();
a.phone::get();
■ 3월 9일 - 6일차
플레이어와 몬스터 클래스 만들기
몬스터는 여러 종류를 가지고 있고
플레이어도 있음
이들의 공통으로는 캐릭터임
#include <iostream>
using namespace std;
class crt {
protected:
int hp;
int pw;
public:
crt(int a1, int a2) :hp(a1), pw(a2) {}
void get_damage(int t_pw) { //플레이에서 crt로 이동
hp -= t_pw;
cout << t_pw << " 데미지 입음 현재 HP : " << this->hp << endl;
}
};
class play : public crt {
public:
play(int a1, int a2) : crt(a1, a2){}
};
class mon : public crt {
protected:
mon(int a1, int a2):crt(a1, a2){}
public:
void sp_at(play* tg) {
tg->get_damage(this->pw * 2);
}
void at(play* tg) {
tg->get_damage(this->pw);
}
};
class smon : public mon {
public:
smon(int a1, int a2) : mon(a1, a2){}
};
class bmon : public mon {
public:
bmon(int a1, int a2) : mon(a1, a2) {}
void sp_at(play* tg) {
tg->get_damage(this->pw * 3);
}
};
int main() {
play hong(100, 10);
bmon tr(200, 15);
smon go(100, 5);
tr.sp_at(&hong);
go.sp_at(&hong);
return 0;
}
다이아몬드 상속
부모1
자식1(부모), 자식2(부모)
손자1(자식1, 자식2) 다중상속
예시 파워
스캐너, 프린터 는 파워를 상속
복사기는 스캐너와 프린터를 다중상속
#include <iostream>
using namespace std;
class pw {
public:
int i;
pw(int a) {
cout << "파워 " << a << endl;
}
};
class sc : public pw {
public:
sc(int a, int b) : pw(b) {
cout << "스캐너 " << a << endl;
}
};
class pt : public pw {
public:
pt(int a, int b) : pw(b) {
cout << "프린트 " << a << endl;
}
};
class cp : public sc, public pt {
public:
cp(int a, int b, int c) :sc(a, c), pt(b, c) {
}
};
int main() {
cp a(5, 11, 1);
return 0;
}
==========출력==========
파워 1
스캐너 5
파워 1
프린트 11
파워가 스캐너와 프린트가 생성되면서 정상적으로 생성된것으로 보임
그러나 주소값이 다름
즉 또다른 파워라는 부모가 두개가 생긴것과 동일한 현상처럼 됨
cout << &a.sc::pw::i << endl;
cout << &a.pt::pw::i << endl;
==========출력==========
파워 1
스캐너 5
파워 1
프린트 11
0000008FB513FC38
0000008FB513FC3C
해결은 부모(파워)를 불러올때 virtual public으로 불러와야함
그렇게 한후 cp클래스에 pw를 추가시켜줌
class sc : virtual public pw
class pt : virtual public pw
class cp : public sc, public pt {
public:
cp(int a, int b, int c) :sc(a, c), pt(b, c), pw(c) {
}
};
==========출력==========
파워 1
스캐너 5
프린트 11
00000085E44FFB28
00000085E44FFB28
클래스의 다형성
들어가기 앞서 포인터로 자식 클래스 활성화
부모 클래스로 * 자식클래스로 만들어진 주소값을 받으면
부모에서 사용하던 함수를 사용, 그러나 변수는 자식것 사용
자식에서의 오버라이딩 되어 있는 개념은 사용하지 않음
#include <iostream>
using namespace std;
class animal {
protected:
string a_name;
public:
animal(string name) : a_name(name) {
}
string getname() {
return a_name;
}
void speak() const { // 상수 클래스로 수정 불가
cout << a_name << " ???" << endl;
}
};
class cat : public animal {
public:
cat(string name) : animal(name) {
}
void speak() const {
cout << a_name << " 야옹" << endl;
}
};
class dog : public animal {
public:
dog(string name) : animal(name) {
}
void speak() const {
cout << a_name << " 멍멍" << endl;
}
};
int main() {
animal a("동물");
cat c("고양이");
dog d("강아지");
a.speak();
c.speak(); // speak()함수를 재 정의(오버라이딩)한상태
d.speak(); // 강아지 멍멍
d.animal::speak(); // 강아지 ???
animal* pa1 = &c; // pa1에 c의 주소값 저장
animal* pa2 = &d; // pa2에 d의 주소값 저장
pa1->speak(); // 고양이 ??? cat의 주소를 담지만 pa1자체는 animal 타입
pa2->speak(); // 강아지 ???
return 0;
}
==========출력==========
동물 ???
고양이 야옹
강아지 멍멍
강아지 ???
고양이 ???
강아지 ???
virtual 가상함수
클래스 추가 돼지, 닭
class pig : public animal {
public:
pig(string name) : animal(name) {
}
void speak() const {
cout << a_name << " 꿀꿀" << endl;
}
};
class chicken : public animal {
public:
chicken(string name) : animal(name) {
}
void speak() const {
cout << a_name << " 꼬끼오" << endl;
}
};
main
다형성을 사용하지 않을 시 자식마다 일일이
자식타입의 변수로 멤버 함수를 호출해야 하는 번거로움이 따른다.
ex)
c.speak();
d.speak();
p.speak();
ck.speak();
int main() {
cat c("고양이");
dog d("강아지");
pig p("돼지");
chicken ck("닭");
c.speak(); // 일일이 만들기 번거로움
// 배열형태로 만들어서 반복문 사용
animal* a[] = { &c, &d, &p, &ck };
for (int i = 0; i < 4; i++) {
a[i]->speak();
}
return 0;
}
==========출력==========
고양이 ???
강아지 ???
돼지 ???
닭 ???
virtual 가상 함수부모 타입 포인터로 자식 객체를 가리킬시 자식이 오버라이딩 한 것을호출하게 하고 싶은 멤버 함수를 virtual 가상 함수로 지정하면 된다.
즉 부모 타입의 포인터로 호출하더라도 자식 클래스가 오버라이딩 한 함수를 호출함
virtual void speak() const { // 상수 클래스로 수정 불가
cout << a_name << " ???" << endl;
}
자식 함수가 오버라이딩 되어 있으면 오버라이딩 출력
int main() {
cat c("고양이");
dog d("강아지");
pig p("돼지");
chicken ck("닭");
animal* a[] = { &c, &d, &p, &ck };
for (int i = 0; i < 4; i++) {
a[i]->speak();
}
return 0;
}
==========출력==========
고양이 야옹
강아지 멍멍
돼지 꿀꿀
닭 꼬끼오
아니면 부모것 출력
class chicken : public animal {
public:
chicken(string name) : animal(name) {
}
/*void speak() const {
cout << a_name << " 꼬끼오" << endl;
}*/
};
==========출력==========
고양이 야옹
강아지 멍멍
돼지 꿀꿀
닭 ???
레퍼런스 사용 // 포인터와 차이 확인
int main() {
cat c("고양이");
dog d("강아지");
pig p("돼지");
chicken ck("닭");
animal& r1 = c;
r1.speak();
return 0;
}
가상함수 override
오버라이딩이 되었는지 함수 작성시 확인
virtual은 자식클래스로 하여금 오버라이딩이 될것을 권장함.
override는 오버라이딩 한 함수라고 강조해주며 오버라이딩이 제대로 안됐을시
컴파일 에러를 발생시킴
virtual 아닐때는 오버라이딩 하는게 문제가 있을 수 있음. 오류발생
class a {
public:
void pt(int x) {
cout << "a : " << x << endl;
}
};
class b : public a {
public: // virtual 되어 있지 않아서 오류
void pt(int x) override {
cout << "b : " << x << endl;
}
};
class c : public b {
public:
void pt(int x) {
cout << "c : " << x << endl;
}
};
virtual 이더라도 받는 인수가 다를때
즉 오버라이딩이 아닌 오버로딩이 되어 있으면 에러
class a {
public:
virtual void pt(int x) {
cout << "a : " << x << endl;
}
};
class b : public a {
public: // int가 아니어서 오류
void pt(char x) override {
cout << "b : " << x << endl;
}
};
오버라이딩 이어도 부모는 const 자식은 변수형일 경우 에러
class a {
public:
virtual void pt(int x) const {
cout << "a : " << x << endl;
}
};
class b : public a {
public: // const가 아니어서 오류
void pt(int x) override {
cout << "b : " << x << endl;
}
};
가상함수 final
두번째 클래스부터 이후에는 오버라이딩하지 않을때 사용
class a {
public:
virtual void pt(int x) {
cout << "a : " << x << endl;
}
};
class b : public a {
public:
void pt(int x) override final {
cout << "b : " << x << endl;
}
};
class c : public b {
public: // 2번째b 클래스에서 final로 오버라이딩를 막음 오류
void pt(int x) {
cout << "c : " << x << endl;
}
};
new 동적할당
#include <iostream>
using namespace std;
class pp {
public:
string name;
int age;
pp(){}
pp(string a, int b) :name(a), age(b) {}
void pr() {
cout << "이름 : " << name << "(" << age << ")" << endl;
}
};
pp* mpc(string* n, int* a, int l) {
pp* np = new pp[l];
for (int i = 0; i < l; i++) {
np[i] = pp(n[i], a[i]);
}
return np;
}
int main() {
string narr[5] = {"홍길동","백두산","한라산","한강","금강"};
int aarr[5] = { 22,26,37,65,22 };
pp* p = mpc(narr, aarr, 5);
p[0].pr();
return 0;
}
■ 3월 15일 - 7일차
연산자 오버로딩
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class n {
private:
int n1, n2;
public:
n(int a, int b) : n1(a), n2(b) {
}
void sn() {
cout << "n1 : " << n1 << ", n2 : " << n2 << endl;
}
};
int main() {
n nc1(10, 20);
n nc2(5, 2);
n re = nc1 + nc2; // + 오류
nc1.sn();
nc2.sn();
return 0;
}
해결방법
n operator+(n& ref) {
return n(n1 + ref.n1, n2 + ref.n2);
}
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class n {
private:
int n1, n2;
public:
n(int a, int b) : n1(a), n2(b) {
}
void sn() {
cout << "n1 : " << n1 << ", n2 : " << n2 << endl;
}
n operator+(n& ref) {
return n(n1 + ref.n1, n2 + ref.n2);
}
};
int main() {
n nc1(10, 20);
n nc2(5, 2);
n re = nc1 + nc2;
nc1.sn();
nc2.sn();
re.sn();
return 0;
}
==========출력==========
n1 : 10, n2 : 20
n1 : 5, n2 : 2
n1 : 15, n2 : 22
- 연산자 추가
n operator-(n& ref) {
return n(n1 - ref.n1, n2 - ref.n2);
}
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class n {
private:
int n1, n2;
public:
n(int a, int b) : n1(a), n2(b) {
}
void sn() {
cout << "n1 : " << n1 << ", n2 : " << n2 << endl;
}
n operator+(n& ref) {
return n(n1 + ref.n1, n2 + ref.n2);
}
n operator-(n& ref) {
return n(n1 - ref.n1, n2 - ref.n2);
}
};
int main() {
n nc1(10, 20);
n nc2(5, 2);
n re = nc1 + nc2;
n re2 = nc1 - nc2;
nc1.sn();
nc2.sn();
re.sn();
re2.sn();
return 0;
}
==========출력==========
n1 : 10, n2 : 20
n1 : 5, n2 : 2
n1 : 15, n2 : 22
n1 : 5, n2 : 18
n re = nc1 + 10; 계산하는 연산자 오버로딩
n operator +(int a) {
return n(n1 + a, n2 + a);
}
곱하기 나누기도 해보기
n operator * (n& ref) {
return n(n1 * ref.n1, n2 * ref.n2);
}
n operator / (n& ref) {
return n(n1 / ref.n1, n2 / ref.n2);
}
전역 함수 오버로딩
n f = 10 + nc1; 에러발생
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class n {
private:
int n1, n2;
public:
n(int a, int b) : n1(a), n2(b) {
}
void sn() {
cout << "n1 : " << n1 << ", n2 : " << n2 << endl;
}
n operator +(int a) {
return n(a + n1, a + n2); //순서를 바꿔도 아래 n f = 10+nc1은 에러
}
};
int main() {
n nc1(10, 20);
n f = 10 + nc1; // 에러발생
nc1.sn();
f.sn();
return 0;
}
==========출력==========
해결방안
friend n operator+(int a, n b); // 클래스에 추가
//전역함수
n operator+(int a, n b) {
b.n1 += a;
b.n1 += a;
return b;
}
전체
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class n {
private:
int n1, n2;
public:
n(int a, int b) : n1(a), n2(b) {
}
void sn() {
cout << "n1 : " << n1 << ", n2 : " << n2 << endl;
}
n operator +(int a) {
return n(n1 + a, n2 + a);
}
friend n operator+(int a, n b);
};
n operator+(int a, n b) {
b.n1 += a;
b.n1 += a;
return b;
}
int main() {
n nc1(10, 20);
n f = 10 + nc1 + 40;
n f2 = 10 + nc1;
nc1.sn();
f.sn();
f2.sn();
return 0;
}
==========출력==========
n1 : 10, n2 : 20
n1 : 70, n2 : 60
n1 : 30, n2 : 20
단항 연산자 오버로딩
n++, ++n
n() 제작
n() {
}
++nc
n operator++() { //++nc = nc.operator++(); 전위 증가 연산
n1 += 1;
n2 += 1;
return *this;
}
nc++
n operator++(int) { //nc++ = nc.operator++(int); 후위 증가 연산
n tem(*this);
n1 += 1;
n2 += 1;
return tem;
}
전체식
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class n {
private:
int n1, n2;
public:
n() {
}
n(int a, int b) : n1(a), n2(b) {
}
void sn() {
cout << "n1 : " << n1 << ", n2 : " << n2 << endl;
}
n operator++() { //++nc = nc.operator++(); 전위 증가 연산
n1 += 1;
n2 += 1;
return *this;
}
n operator++(int) { //nc++ = nc.operator++(int); 후위 증가 연산
n tem(*this);
n1 += 1;
n2 += 1;
return tem;
}
};
int main() {
n nc1(10, 20);
n nc2;
nc1.sn();
nc2.sn();
cout << endl;
nc2 = nc1++;
cout << "nc2 : ";
nc2.sn();
cout << "nc1 : ";
nc1.sn();
cout << endl;
nc2 = ++nc1;
cout << "nc2 : ";
nc2.sn();
cout << "nc1 : ";
nc1.sn();
return 0;
}
==========출력==========
n1 : 10, n2 : 20
n1 : -858993460, n2 : -858993460
nc2 : n1 : 10, n2 : 20
nc1 : n1 : 11, n2 : 21
nc2 : n1 : 12, n2 : 22
nc1 : n1 : 12, n2 : 22
대입 연산자 오버로딩
#include <iostream>
using namespace std;
#define pr(a) cout << a << endl;
class n {
private:
int n1, n2;
public:
n() {
}
n(int a, int b) : n1(a), n2(b) {
}
void sn() {
cout << "n1 : " << n1 << ", n2 : " << n2 << endl;
}
};
int main() {
n nc1(10, 20);
n nc2;
nc2.sn();
nc2 = nc1;
nc2.sn();
return 0;
}
==========출력==========
n1 : -858993460, n2 : -858993460
n1 : 10, n2 : 20
탬플릿
함수나 클래스를 만들때는 자료형을 넣어줘야함
탬플릿은 자료형을 넣을 필요 없이 자동적으로 처리해줌
그러나 탬플릿으로 만들어진 함수에는 숫자를 넣지 못하고 변수를 넣어줘야함
함수 탬플릿
#include <iostream>
using namespace std;
template<typename t>
void sw(t& a, t& b) {
t c = a;
a = b;
b = c;
}
int main()
{
// double a = 10.2, b = 5.2; // int string 아무런 차이 없음
string a = "이순신", b="홍길동";
// sw(10.2, 5.2); //에러
sw(a,b);
cout << a << " " << b << endl;
return 0;
}
==========출력==========
홍길동 이순신
명시적 특수화(explicit specialization)
- 함수 템플릿은 특정 타입에 대한 명시적 특수화를 제공하여, 해당 타입에 대해 특별한 동작을 정의할 수 있게 해줌, 컴파일러는 호출된 함수에 정확히 대응하는 특수화된 정의를 발견하면, 더는 템플릿을 찾지 않고 해당 정의를 사용합니다.
#include <iostream>
using namespace std;
template<typename t>
void sw(t& a, t& b) {
t c = a;
a = b;
b = c;
}
template <>void sw<double>(double& a, double& b) {
a += b;
};
int main() {
int a=20, b=30;
double c = 3.14, d = 4.52;
sw(c, d);
cout << c << " " << d << endl;
return 0;
}
================================================
7.66 4.52
클래스 탬플릿
C++에서 클래스 템플릿(class template)이란 클래스의 일반화된 선언을 의미합니다.
앞서 살펴본 함수 템플릿과 동작은 같으며, 그 대상이 함수가 아닌 클래스라는 점만 다릅니다.
클래스 템플릿을 사용하면, 타입에 따라 다르게 동작하는 클래스 집합을 만들 수 있습니다.
즉, 클래스 템플릿에 전달되는 템플릿 인수(template argument)에 따라 별도의 클래스를 만들 수 있게 됩니다.
이러한 템플릿 인수는 타입이거나 명시된 타입의 상숫값일 수 있습니다.
#include <iostream>
using namespace std;
template<typename t>
class c {
private:
t data;
public:
c(t a) : data(a) {
}
void sp() {
cout << data << endl;
}
};
int main()
{
c<int> d1 = c<int>(50);
d1.sp();
c<char> d2('a');
d2.sp();
c<float> d3(3.14);
d3.sp();
c<string> d4("홍길동");
d4.sp();
return 0;
}
==========출력==========
50
a
3.14
홍길동
중첩 클래스 탬플릿
클래스나 클래스 템플릿 내에 또 다른 템플릿을 중첩하여 정의할 수 있음
#include <iostream>
using namespace std;
template<typename t>
class c {
private:
t data;
public:
template<typename u>
class ci {
public:
u id;
ci(u a) :id(a) {
}
void pr() {
cout << "내부 " << id << endl;
}
};
c(t a) : data(a) {
}
void sp() {
cout << data << endl;
}
};
int main()
{
c<int> d1 = c<int>(50);
d1.sp();
c<int>::ci<int> a = c<int>::ci<int>(100);
a.pr();
return 0;
}
명시적 특수화(explicit specialization)
- 클래스 템플릿은 특정 타입에 대한 명시적 특수화를 제공하여, 해당 타입에 대해 특별한 동작을 정의할 수 있게 해줌, 컴파일러는 호출된 함수에 정확히 대응하는 특수화된 정의를 발견하면, 더는 템플릿을 찾지 않고 해당 정의를 사용합니다.
#include <iostream>
using namespace std;
template<typename t>
class c {
private:
t data;
public:
c(t a) : data(a) {
}
void sp() {
cout << data << endl;
}
};
template <> class c<double> {
private:
double data;
public:
c(double a) : data(a+10) {
}
void sp() {
cout << data << endl;
}
};
int main()
{
c<double> d1 = c<double>(5.7);
d1.sp();
return 0;
}
계좌 입금, 출금 출력, 이자율
#include <iostream>
#include <vector>
using namespace std;
class Account {
private:
string name;
int val;
public:
Account(string a, int b):name(a),val(b){}
void show() const {
cout << "이름 : " << name << " 잔액 : " << val << "원" << endl;
}
void dp(int a) { //계좌 입급
val += a;
show();
}
void wd(int b) { //계좌 출금
if (val < b) {
cout << "잔액부족" << endl;
}
else {
val -= b;
show();
}
}
void ru(int r) {
int a = val * r / 100;
val = val + a;
}
};
class Bank {
private:
vector <Account> accs; //벡터로 계좌를 저장할 수 있는 변수
public:
void add(string a, int b) { //계좌 추가
accs.push_back(Account(a, b));
}
void showAll() { //뱅크내 전체 계좌 출력
for (Account a : accs) {
a.show();
}
}
void dpa(int in, int va) {
if (in < 0 || in >= accs.size()) {
return;
}
else {
accs[in].dp(va);
}
}
void wda(int in, int va) {
if (in < 0 || in >= accs.size()) {
return;
}
else {
accs[in].wd(va);
}
}
void ruAll(int z) { //뱅크내 전체 이자율
for (Account& a : accs) {
a.ru(z);
}
}
};
int main() {
Bank kb;
kb.add("홍길동", 10000);
kb.add("이순신", 2000);
kb.add("신사", 5000);
kb.ruAll(5);
kb.showAll();
return 0;
}
■ 3월 16일 - 8일차
○ 찾아서 인덱스 나오게 하기 아니면 -1
class Account{
string gn() {
return name;
}
};
class Bank{
int fna(string a) {
for (int i = 0; i < accs.size(); i++) {
if (accs[i].gn() == a) {
return i;
}
}
return -1;
}
};
○ 계좌 삭제 없으면 미삭제
void rea(string a) {
int ix = fna(a);
if (ix == -1) {
cout << "해당 이름 계좌 없음" << endl;
}
else {
accs.erase(accs.begin() + ix);
}
}
○ 입출금 내역 저장 클래스 만들기
class Dpwdh {
string dw;
int v;
public:
Dpwdh(string a, int b) :dw(a), v(b) {}
void pr() {
cout << dw << " " << v << "원" << endl;
}
};
class Account {
vector<Dpwdh> dwh; //추가
void dp(int a) { //수정
val += a;
show();
dwh.push_back(Dpwdh("입금",a)); //추가
}
void wd(int b) { //수정
if (val < b) {
cout << "잔액부족" << endl;
}
else {
val -= b;
show();
dwh.push_back(Dpwdh("출금", b)); //추가
}
}
void dwhshow() { //추가
for (Dpwdh a : dwh) {
a.pr();
}
}
};
class Bank {
void dwhnshow(string a) { //추가
int ix = fna(a);
if (ix == -1) {
cout << "해당 이름 계좌 없음" << endl;
}
else {
accs[ix].dwhshow();
}
}
};
○ 뱅크 관리 시스템 제작 초기화시 3명 정보 등록
class BankSystem {
private:
Bank bank;
public:
BankSystem(){
bank.add("홍길동", 30000);
bank.add("이순신", 50000);
bank.add("백두산", 10000);
}
void run() {
while (true) {
cout << endl << "1.개설 2.조회 3.입금 4. 출금 5. 이자율 6. 계좌 삭제 7. 입출금 내역 8. 종료" << endl;
cout << "선택: ";
int c;
cin >> c;
if (c == 1) { // 계좌 개설
string n;
int v;
cout << "이름: ";
cin >> n;
cout << "금액: ";
cin >> v;
bank.add(n, v);
}
else if (c == 2) { // 계좌 조회
bank.showAll();
}
else if (c == 3) { // 입금
string n;
int v;
cout << "이름: ";
cin >> n;
cout << "입금액: ";
cin >> v;
int ix = bank.fna(n);
if (ix == -1) {
cout << "계좌를 찾을 수 없습니다.\n";
}
else {
bank.dpa(ix,v);
}
}
else if (c == 4) { // 출금
string n;
int v;
cout << "이름: ";
cin >> n;
cout << "출금액: ";
cin >> v;
int ix = bank.fna(n);
if (ix == -1) {
cout << "계좌를 찾을 수 없습니다.\n";
}
else {
bank.wda(ix, v);
}
}
else if (c == 5) { // 이자율 적용
int rate;
cout << "적용 이자율 (%): ";
cin >> rate;
bank.ruAll(rate);
}
else if (c == 6) { // 계좌 삭제
string n;
cout << "이름: ";
cin >> n;
bank.rea(n);
}
else if (c == 7) { // 입출금 내역 조회
string n;
cout << "이름: ";
cin >> n;
bank.dwhnshow(n);
}
else if (c == 8) { // 종료
cout << "종료" << endl;
break;
}
else {
cout << "올바로 선택하세요";
}
}
}
};
int main() {
BankSystem s;
s.run();
return 0;
return 0;
}
● 최종
#include <iostream>
#include <vector>
using namespace std;
class Dpwdh {
string dw;
int v;
public:
Dpwdh(string a, int b):dw(a),v(b){}
void pr() {
cout << dw << " " << v << "원" << endl;
}
};
class Account {
private:
string name;
int val;
public:
vector <Dpwdh> dwh;
Account(string a, int b) :name(a), val(b) {}
void show() const {
cout << "이름 : " << name << " 잔액 : " << val << "원" << endl;
}
void dp(int a) { //계좌 입급
val += a;
show();
dwh.push_back(Dpwdh("입금",a));
}
void wd(int b) { //계좌 출금
if (val < b) {
cout << "잔액부족" << endl;
}
else {
val -= b;
show();
dwh.push_back(Dpwdh("출금", b));
}
}
void ru(int r) {
int a = val * r / 100;
val = val + a;
}
string gn() {
return name;
}
void dwhshow() {
for (Dpwdh a : dwh) {
a.pr();
}
}
};
class Bank {
private:
vector <Account> accs; //벡터로 계좌를 저장할 수 있는 변수
public:
void add(string a, int b) { //계좌 추가
accs.push_back(Account(a, b));
}
void showAll() { //뱅크내 전체 계좌 출력
for (Account a : accs) {
a.show();
}
}
void dpa(int in, int va) {
if (in < 0 || in >= accs.size()) {
return;
}
else {
accs[in].dp(va);
}
}
void wda(int in, int va) {
if (in < 0 || in >= accs.size()) {
return;
}
else {
accs[in].wd(va);
}
}
void ruAll(int z) { //뱅크내 전체 이자율
for (Account& a : accs) {
a.ru(z);
}
}
int fna(string a) { //이름을 찾아서 인덱스 반환
for (int i = 0; i < accs.size(); i++) {
if (accs[i].gn() == a) {
return i;
}
}
return -1;
}
void rea(string a) {//이름으로 삭제
int ix = fna(a);
if (ix == -1) {
cout << "계좌없음" << endl;
}
else {
accs.erase(accs.begin() + ix);
}
}
void dwhnshow(string a) {
int ix = fna(a);
if (ix == -1) {
cout << "계좌 없음" << endl;
}
else {
accs[ix].dwhshow();
}
}
};
class BankSystem {
private:
Bank bank;
public:
BankSystem() {
bank.add("1", 30000);
bank.add("2", 50000);
bank.add("3", 10000);
}
void run() {
while (true) {
cout << endl << "1.개설 2.조회 3. 입금 4.출금 5.이자율 6.계좌삭제 7.입출금내역 8. 종료" << endl;
cout << "선택 : ";
int c;
cin >> c;
if (c == 1) { //계좌 개설
string n;
int v;
cout << "이름 : ";
cin >> n;
cout << "금액 : ";
cin >> v;
bank.add(n, v);
}
else if (c == 2) { //계좌조회
bank.showAll();
}
else if (c == 3) { //입금
string n;
int v;
cout << "이름 : ";
cin >> n;
cout << "입금액 : ";
cin >> v;
int ix = bank.fna(n);
if (ix == -1) {
cout << "계좌 없음" << endl;
}
else {
bank.dpa(ix, v);
}
}
else if (c == 4) { //출금
string n;
int v;
cout << "이름 : ";
cin >> n;
cout << "출금액 : ";
cin >> v;
int ix = bank.fna(n);
if (ix == -1) {
cout << "계좌 없음" << endl;
}
else {
bank.wda(ix, v);
}
}
else if (c == 5) { //이자율
int r;
cout << "이자율(%) : ";
cin >> r;
bank.ruAll(r);
}
else if (c == 6) { //계좌 삭제
string n;
cout << "이름 : ";
cin >> n;
bank.rea(n);
}
else if (c == 7) { //입출금 조회
string n;
cout << "이름 : ";
cin >> n;
bank.dwhnshow(n);
}
else if (c == 8) { //종료
cout << "종료" << endl;
break;
}
else {
cout << "제대로 입력 하세요" << endl;
}
}
}
};
int main() {
BankSystem bs;
bs.run();
return 0;
}
■ 주식프로그램
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
using namespace std;
class Stock {
public:
int id;
string name;
int price;
vector<int> history;
Stock(int i, string n, int p) :id(i), name(n), price(p) {
history.push_back(p);
}
void udprice() { //랜덤하게 증감하기 -10~10%
double change = (rand() % 21 - 10) / 100.0;
price += price * change;
history.push_back(price);
}
};
class Market {
};
int main() {
srand(time(0));
Stock 삼성(1, "삼성", 10000);
삼성.udprice();
삼성.udprice();
삼성.udprice();
삼성.udprice();
for (int a : 삼성.history) {
cout << a << endl;
}
return 0;
}
○ 전체 목록 출력
class Stock {
public:
void show() const { // 개별 주식 정보 출력
cout << "현재가 : " << price << "원 | " << name << endl;
}
};
class Market {
public:
vector<Stock> stocks;
Market() {
stocks.push_back(Stock(0, "삼성", 20000));
stocks.push_back(Stock(1, "애플", 30000));
stocks.push_back(Stock(2, "테슬라", 5000));
stocks.push_back(Stock(3, "현대", 3000));
}
void showAll() { // 전체 주식 목록 출력
cout << endl << "===== 현재 시장 주식 목록 =====" << endl;
for (auto& stock : stocks) {
stock.show();
}
}
};
class MarketSystem {
public:
Market market;
void play() {
while (true) {
cout << "\n\n메뉴 1. 전체목록 5.종료 \n\n";
cout << "입력 >> ";
int c;
cin >> c;
if (c == 1) {
market.showAll();
}
else if (c == 5) {
break;
}
}
}
};
int main() {
srand(time(0));
MarketSystem kospi;
kospi.play();
return 0;
}
○ 목록, 변화 시간, 종료
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
using namespace std;
class Stock {
public:
int id;
string name;
int price;
vector<int> history;
Stock(int a, string b, int c):id(a),name(b),price(c) {
history.push_back(c);
}
void upprice() {
double ch = (rand() % 21 - 10) / 100.0;
price += (int)(price * ch);
history.push_back(price);
}
void show() {
cout << "현재가 : " << price << "원 | " << name << endl;
}
void hshow() {
int c = 1;
for (auto& i : history) {
cout << c++ << "일차 : " << i << "원" << endl;
}
}
};
class Market {
public:
vector<Stock> stocks;
Market() {
stocks.push_back(Stock(0, "삼성", 20000));
stocks.push_back(Stock(1, "애플", 100000));
stocks.push_back(Stock(2, "테슬라", 30000));
stocks.push_back(Stock(3, "현대", 5000));
}
void showAll() {
cout << endl << "======== 시장 주식 목록 ==========" << endl;
for (auto& i : stocks) {
i.show();
}
}
void udo() {
for (auto& i : stocks) {
i.upprice();
}
}
void ud() {
cout << "몇일 : ";
int d;
cin >> d;
for (int i = 0; i < d; i++) {
udo();
}
}
void hshowAll() {
for (auto& i : stocks) {
cout << i.id << " " << i.name << " ";
}
int c;
cout << endl << ">> ";
cin >> c;
stocks[c].hshow();
}
void lshow() {
for (auto& i : stocks) {
cout << i.id << " " << i.name << " ";
}
int c;
cout << endl << ">> ";
cin >> c;
stocks[c].show();
}
};
class MarketSystem {
public:
Market mar;
void play() {
while (true) {
cout << "\n메뉴 1.전체목록 2.주식현재 3.변화 4.시간 5.종료 \n\n";
int c;
cout << "입력 : ";
cin >> c;
if (c == 1) {
mar.showAll();
}
else if (c == 2) {
mar.lshow();
}
else if (c == 3) {
mar.hshowAll();
}
else if (c == 4) {
mar.ud();
}
else if (c == 5) {
break;
}
else {
cout << "잘못입력" << endl;
}
}
}
};
int main() {
srand(time(0));
MarketSystem kospi;
kospi.play();
return 0;
}
'언어 수업자료 > C언어' 카테고리의 다른 글
C언어 25-01 방특 (0) | 2025.01.31 |
---|---|
C언어 25-01 주말 (0) | 2025.01.11 |
C언어 3 (0) | 2024.06.15 |
C언어 2 (0) | 2024.05.18 |
C언어 1 (0) | 2024.04.20 |