반응형
PART 2. 객체 지향 프로그래밍
- chapter 10. 프렌드와 연산자 중복
1. friend 키워드
- 기본적으로 private로 선언된 멤버들은 외부에서 접근할 수 없다. 심지어는 상속받은 클래스도 부모의 private 멤버들에는 접근할 수 없다.
- friend 키워드는 선언한 쪽의 private 멤버를 외부에서 접근할 수 있도록 허용한다는 의미이다.
- friend 지정은 단방향으로 명시적으로 지정한 대상에만 적용된다.
- friend 지정은 전이되지 않으며 friend의 friend는 인정되지 않는다.
- friend 지정은 상속되지 않는다.
- friend 지정은 클래스 내에서만 할 수 있고, 다른 클래스, 다른 클래스의 멤버 함수, 전역 함수에 할 수 있다.
Header.h
#pragma once #include <iostream> #include <string> #include <ctime> #include <tchar.h> using std::cout; using std::cin; using std::endl; using std::string;
Card_one.h
#pragma once #include "Header.h" //전방선언. 이런 클래스가 나올거라고 알려주는 의미. class Card_deck; const char SPADE[3] = "♠"; const char DIAMOND[3] = "◆"; const char HEART[3] = "♥"; const char CLUB[3] = "♣"; class Card_one { int pattern; int number; bool open; bool showData(); bool setOpen(bool onoff); bool getOpen(); //생성자도 private이므로 일반적인 방법으로는 객체 생성이 안되는 클래스. Card_one(); Card_one(int p, int n); ~Card_one(); //카드 덱 클래스를 friend 지정. friend class Card_deck; };
Card_one.cpp
#include "Card_one.h" bool Card_one::showData() { if (open == true) { switch (pattern) { case 0: cout << SPADE; break; case 1: cout << DIAMOND; break; case 2: cout << HEART; break; case 3: cout << CLUB; break; } switch (number) { case 1: cout << " A"; break; case 11: cout << " J"; break; case 12: cout << " Q"; break; case 13: cout << " K"; break; default: cout << " " << number; break; } cout << endl; return true; } else { cout << "???" << endl; return false; } } bool Card_one::setOpen(bool onoff) { open = onoff; return open; } bool Card_one::getOpen() { return open; } Card_one::Card_one() { pattern = 0; number = 0; open = false; } Card_one::Card_one(int p, int n) { pattern = p; number = n; open = false; } Card_one::~Card_one() { }
Card_deck.h
#pragma once //friend 지정된 클래스에서는 해당 클래스에 대한 완전한 정보가 필요하다. #include "Card_one.h" class peep_deck { public: void peep_ok(Card_deck& D); //void peep_no(Card_deck& D); peep_deck() {} ~peep_deck() {} }; class Card_deck { private: Card_one Deck[52]; int currentCnt; public: void swapCard(Card_one& srcCard, Card_one& dstCard); void Shuffle(int cnt); void cardOpen(); Card_deck(); virtual ~Card_deck(); //friend 전역 함수 선언. //CntChoice 함수는 전역 함수가 되므로 Card_deck클래스의 멤버가 아니게 된다. friend void CntChoice(Card_deck&p, int n) { p.currentCnt = n; } //peep_deck 클래스의 peep_ok()메소드만 friend 지정 //특정 클래스의 멤버를 friend로 선언하려면 그 클래스의 선언이 이 클래스의 앞에 있고, 멤버 함수의 몸체는 뒤에 있어야 한다. friend void peep_deck::peep_ok(Card_deck& D); };
Card_deck.cpp
#include "Card_deck.h" Card_deck::Card_deck() { //카드 세팅 for (int iCnt = 0; iCnt < 52; iCnt++) { switch (iCnt / 13) { case 0: Deck[iCnt] = Card_one(0, iCnt % 13 + 1); break; case 1: Deck[iCnt] = Card_one(1, iCnt % 13 + 1); break; case 2: Deck[iCnt] = Card_one(2, iCnt % 13 + 1); break; case 3: Deck[iCnt] = Card_one(3, iCnt % 13 + 1); break; } //특수문자는 char형의 표현범위를 벗어나기 때문에 경고가 발생한다. //C언어에서 특수문자나 다국어 처리는 상당히 까다로운 부분. //일단 여기서는 char를 wchar_t로 바꾸는 것으로 해결했다. //참고 : 멀티바이트, 유니코드, ICU(International Components for Unicode) } currentCnt = 0; } void Card_deck::swapCard(Card_one& srcCard, Card_one& dstCard) { Card_one temp = srcCard; srcCard = dstCard; dstCard = temp; } void Card_deck::Shuffle(int cnt) { srand((unsigned)time(NULL)); cout << "덱을 " << cnt << "번 섞습니다." << endl; for (int iCnt = 0; iCnt < cnt; iCnt++) { int src = rand() % 52; int dst = rand() % 52; swapCard(Deck[src], Deck[dst]); } cout << "덱을 섞었습니다." << endl; } void Card_deck::cardOpen() { Deck[currentCnt].open = true; Deck[currentCnt].showData(); currentCnt++; } Card_deck::~Card_deck() { } void peep_deck::peep_ok(Card_deck& D) { D.cardOpen(); D.currentCnt--; } //friend 선언 안한 함수에서는 접근 불가. //void peep_deck::peep_no(Card_deck& D) //{ // D.cardOpen(); // D.currentCnt--; //}
main.cpp
#include "Card_deck.h" int main() { Card_deck deck; deck.Shuffle(100); deck.cardOpen(); //전역 함수가 되었으므로 볼 수 없다. //deck.CntChoice(deck, 42); CntChoice(deck,42); peep_deck pd; pd.peep_ok(deck); }
반응형