231130 C++프로그래밍 13주차
1. C++에서 private과 protected의 접근 속성 공통점과 차이점
[공통점]
'private'과 'protected' 키워드 둘 다 클래스 외부에서의 접근을 제한한다.
이는 클래스의 내부 구조를 보호하고, 데이터의 무분별한 변경을 막는 등의 역할을 한다.
[차이점]
'private' : 이 키워드가 붙은 멤버 변수나 함수는 그 클래스 내부에서만 접근이 가능하다. 따라서 해당 클래스의 인스턴스를 통해서도 접근할 수 없다. 이를 통해 클래스의 내부 데이터를 완전히 캡슐화 할 수 있다.
'protected' : 이 키워드가 붙은 멤버 변수나 함수는 그 클래스 내부 및 상속받은 클래스에서 접근이 가능하다. 이는 상속 관계에서 부모 클래스의 멤버 변수나 함수를 자식 클래스에서 재사용할 필요가 있을 때 유용하다.
2.
#include <iostream>
using std::cout;
using std::endl;
class A1 // 아버지
{
int a;
public:
A1(int i) { a = i; }
int getA() { return a; }
};
class A2 // 어머니
{
int b;
public:
A2(int i) { b = i; }
int getB() { return b; }
};
class B :public A1, public A2
{
// 기본 클래스 A1과 A2로부터
// 상속 받은 파생 클래스
int c;
public:
B(int i, int j, int k) :A1(i), A2(j) { c = k; }
// i는 기본클래스 A1의 생성자로,
// j는 기본클래스 A2의 생성자로
// 각각 매개변수 전달
void show() {
cout << getA() << ' ' << getB() << ' ' << c << endl;
}
};
int main()
{
B bb(1, 2, 3);
bb.show();
return 0;
}
3.
#include <iostream>
using std::cout;
using std::endl;
class B1 { // 'B1'이라는 클래스를 선언합니다. 이 클래스는 아버지 역할을 합니다.
double d; // private 멤버 변수 'd'를 선언합니다.
public: // 이후로 선언되는 멤버들은 public입니다.
B1(double dd) { d = dd; }
// B1 클래스의 생성자를 선언하고, 매개변수로 받은 dd를 멤버 변수 d에 할당합니다.
double getD() { return d; } // d 값을 반환하는 getter 함수를 선언합니다.
};
class B2 { // 'B2'라는 클래스를 선언합니다. 이 클래스는 어머니 역할을 합니다.
int i; // private 멤버 변수 'i'를 선언합니다.
public: // 이후로 선언되는 멤버들은 public입니다.
B2(int ii) { i = ii; }
// B2 클래스의 생성자를 선언하고, 매개변수로 받은 ii를 멤버 변수 i에 할당합니다.
int getI() { return i; } // i 값을 반환하는 getter 함수를 선언합니다.
};
class D :public B1, public B2 {
// 'D'라는 클래스를 선언하고, B1과 B2 클래스를 public으로 상속받습니다.
char c; // private 멤버 변수 'c'를 선언합니다.
public: // 이후로 선언되는 멤버들은 public입니다.
D(double dd, int ii, char cc) :B1(dd), B2(ii)
// D 클래스의 생성자를 선언하고, B1과 B2의 생성자를 초기화 리스트를 통해 초기화합니다.
{
c = cc; // 매개변수로 받은 cc를 멤버 변수 c에 할당합니다.
}
void print() { // 멤버 변수들의 값을 출력하는 함수를 선언합니다.
cout << "Double : " << getD() << endl;
// B1의 멤버 함수인 getD()를 호출하여 d의 값을 출력합니다.
cout << "Int : " << getI() << endl;
// B2의 멤버 함수인 getI()를 호출하여 i의 값을 출력합니다.
cout << "Char : " << c << endl; // 멤버 변수 c의 값을 출력합니다.
}
};
int main() // 메인 함수를 선언합니다.
{
D d(1.23, 10, 'H');
// D 클래스의 객체 d를 생성하고, 생성자에 필요한 매개변수를 전달합니다.
cout << d.getD() << ',' << d.getI() << endl;
// d 객체의 getD(), getI() 멤버 함수를 호출하여 결과를 출력합니다.
d.print(); // d 객체의 print() 멤버 함수를 호출하여 결과를 출력합니다.
return 0; // 프로그램을 종료합니다.
}
4. 여러 개의 기본 클래스를 상속 받을 때, 생성자와 소멸자의실행 순서
- 생성자는 기본 클래스가 지정된 순서대로 왼쪽에서 오른쪽으로 실행되고, 소멸자는 역순으로 실행된다.
#include <iostream>
using std::cout;
class A1 // 기본 클래스 1
{
int a;
public:
A1() { cout << "A1의 생성자.\n"; }
~A1() { cout << "A1의 소멸자.\n"; }
};
class A2 // 기본 클래스 2
{
int b;
public:
A2() { cout << "A2의 생성자.\n"; }
~A2() { cout << "A2의 소멸자.\n"; }
};
class B : public A1, public A2
// 기본 클래스 1과 2로부터
// 상속 받은 파생 클래스
{
int c;
public:
B() { cout << "B의 생성자.\n"; }
~B() { cout << "B의 소멸자.\n"; }
};
int main()
{
B bb;
return 0;
}
5. 이름과 전화번호를 관리(기본클래스 Name, 파생클래스Phone)
• 출력 결과 : Smile Han의 전화번호는1234-5678
• 상속을 이용하여 기존의 Name 클래스를 재사용할 수 있고, 중복되는 코드는 줄일 수 있다.
#include <iostream>
using std::cout;
#include <string>
class Name { //기본 클래스는 이름만 처리
std::string name;
public:
void get_name(std::string s) { name = s; }
void print_name() { cout << name << "의 전화번호는"; }
};
class Phone : public Name { //파생클래스는 전화번호처리
std::string phone;
public:
void get_phone(std::string s) { phone = s; }
void print_phone() {
print_name();
cout << phone;
}
};
int main()
{
Phone h;
h.get_name("Smile Han");
h.get_phone("1234-5678");
h.print_phone();
return 0;
}
6. 5번 소스의 class diagram
7. 수업에서 실습으로 만든 프로그래밍 소스
#include <iostream>
using std::cout;
using std::endl;
using std::string;
class Man {
protected:
string name;
int age;
public:
Man(string name, int age) {
this->name = name;
this->age = age;
}
void m_show() {
cout << "이름 : " << name << endl;
cout << "나이 : " << age << endl;
}
};
class Student : public Man {
string ban;
string hak;
public:
Student(string n, int a, string b, string h) : Man(n,a) {
ban = b;
hak = h;
}
void s_show() {
m_show();
cout << "반 : " << ban << endl;
cout << "학번 : " << hak << endl;
}
};
class Teacher : public Man {
string major;
string subject;
public:
Teacher(string n, int a, string m, string s) : Man(n, a) {
major = m;
subject = s;
}
void t_show() {
m_show();
cout << "전공 : " << major << endl;
cout << "담당과목 : " << subject << endl;
}
};
int main()
{
Student lsy("홍길동", 21, "B반", "200012345");
Teacher hsh("한미소", 40, "전산", "C++프로그래밍");
lsy.s_show();
hsh.t_show();
return 0;
}
8. 7번 소스의 클래스다이어그램
9. 7번 소스를 응용하여 담당교수까지 나타내는 소스
#include <iostream>
using std::cout;
using std::endl;
using std::string;
class Man {
protected:
string name;
int age;
public:
Man(string name, int age) {
this->name = name;
this->age = age;
}
void m_show() {
cout << "이름 : " << name << endl;
cout << "나이 : " << age << endl;
}
};
class Dam {
protected:
string name;
int age;
public:
Dam(string name, int age) {
this->name = name;
this->age = age;
}
void m_show() {
cout << "담당교수의 이름 : " << name << endl;
cout << "나이 : " << age << endl;
}
};
class Student : public Man {
string ban;
string hak;
public:
Student(string n, int a, string b, string h) : Man(n,a) {
ban = b;
hak = h;
}
void s_show() {
m_show();
cout << "반 : " << ban << endl;
cout << "학번 : " << hak << endl;
}
};
class Teacher : public Man {
string major;
string subject;
public:
Teacher(string n, int a, string m, string s) : Man(n, a) {
major = m;
subject = s;
}
void t_show() {
m_show();
cout << "전공 : " << major << endl;
cout << "담당과목 : " << subject << endl;
}
};
class Mteacher : public Dam {
string major;
string subject;
public:
Mteacher(string n, int a, string m, string s) : Dam(n, a) {
major = m;
subject = s;
}
void mt_show() {
m_show();
cout << "전공 : " << major << endl;
cout << "담당과목 : " << subject << endl;
}
};
int main()
{
Student lsy("홍길동", 20, "B반", "200012345");
Teacher hsh("한미소", 40, "전산", "C++프로그래밍");
lsy.s_show();
hsh.t_show();
Student abc("이길동", 21, "B반", "202312345");
Mteacher def("교오수", 40, "회계", "C#프로그래밍");
abc.s_show();
def.mt_show();
return 0;
}
10. virtual : 가상의
부모가 만든 함수 앞에 virtual을 쓰면 부모와 자식이 같은 이름의 함수를 만들었을 때 부모가 만든 함수는 가상의 함수 처리가 되어 자식의 함수가 사용된다.
다음 함수를 출력했을 때, virtual이 없다면 출력문에 Dot::draw()이 출력되지만 virtual이 있다면 line함수의 Line::draw()가 호출된다.
#include <iostream>
using std::cout;
class Dot {
public:
virtual void draw() { cout << "Dot::draw()\n";}
void print() {
cout << "Dot 클래스\n";
draw();
}
};
class Line :public Dot
{
public:
void draw() { cout << "Line::draw()\n";}
};
int main() {
Line line;
line.print();
return 0;
}
11. virtual은 부모에게 쓴다면, override는 자식에게 쓰는 것이다.
위치
- virtual : 함수 앞에 작성
- override : 소괄호 뒤에 작성, 작성하지 않아도 상관없음
#include <iostream>
using std::cout;
class Dot {
public:
void draw() { cout << "Dot::draw()\n";}
void print() {
cout << "Dot 클래스\n";
draw();
}
};
class Line :public Dot
{
public:
void draw() override { cout << "Line::draw()\n";}
};
int main() {
Line line;
line.print();
return 0;
}
참고자료 : 한성현 교수님 수업자료