SA성아 2023. 11. 29. 12:32

상속 (inheritance)


protected와 private의 공통점과 차이점

공통점: 

1. protected와 private 모두 클래스 내부에서 선언된 멤버에 접근할 수 있도록 제한을 둡니다.
2. 두 접근 속성은 외부에서 직접 접근할 수 없으며, 클래스의 메서드를 통해서만 접근할 수 있습니다.
3. protected와 private 멤버는 상속을 통해 파생 클래스에서 접근할 수 있습니다.

차이점: 

1. private 멤버는 해당 멤버를 선언한 클래스 내부에서만 접근할 수 있습니다. 즉, 외부에서는 접근할 수 없습니다. 이는 클래스의 내부 구현 세부 사항을 숨기고, 외부로부터의 직접 접근을 제한하기 위해 사용됩니다.

class Example {
private:
    int privateVar; // private 멤버 변수

protected:
    int protectedVar; // protected 멤버 변수

public:
    void setPrivateVar(int value) {
        privateVar = value;
    }

    int getPrivateVar() {
        return privateVar;
    }
};

class Derived : public Example {
public:
    void accessProtectedVar() {
        protectedVar = 10; // protected 멤버에 접근 가능
    }
};

int main() {
    Example obj;
    obj.setPrivateVar(5); // private 멤버에 접근 가능

    Derived derivedObj;
    derivedObj.accessProtectedVar(); // protected 멤버에 접근 가능

    return 0;
}

 

실습 8-7: 파생 클래스 생성자에서 기본 클래스 생성자에 매개변수전달 형식

#include <iostream>
using std::cout;
using std::endl;
class A {
	int a;
public:
	A(int i) {
		cout << "A의 생성자\n";
		a = i;
	}
	~A() { cout << "A의 소멸자\n"; }
	void showA() { cout << a << '\n'; }
};
class B :public A {
	int b;
public:
	B(int i, int j) :A(i) {// i는 기본클래스 생성자의 매개변수로 전달
		cout << "B의 생성자\n";
		b = j;
	}
	~B() { cout << "B의 소멸자\n"; }
	void showB() { cout << b << endl; }
};

▶ 자식쪽에서 부모쪽의 생성자에 매개변수를 넘기는 방법: 

파생클래스생성자(매개변수 리스트) :기본클래스생성자(매개변수리스트) {
	:
}

 


상속(inheritance) 심화


다중상속을 지원하는 프로그래밍 언어

1. 파이썬 (Python): 파이썬은 다중 상속을 지원하는 대표적인 언어입니다. 클래스 정의 시에 여러 부모 클래스를 지정하여 다중 상속을 구현할 수 있습니다.

class Parent1:
    def method1(self):
        print("Parent1의 메서드")

class Parent2:
    def method2(self):
        print("Parent2의 메서드")

class Child(Parent1, Parent2):
    pass

# Child 클래스는 Parent1과 Parent2 클래스를 다중 상속받습니다.

child = Child()
child.method1()  # Parent1의 메서드
child.method2()  # Parent2의 메서드


2. C++: C++ 역시 다중 상속을 지원하는 언어입니다. 클래스 정의 시에 쉼표로 구분하여 여러 부모 클래스를 지정할 수 있습니다. 다중 상속을 사용할 때는 다이아몬드 상속 등 주의해야 할 점이 있으므로 주의가 필요합니다.
3. Eiffel: Eiffel 언어는 다중 상속을 지원하는 객체 지향 프로그래밍 언어입니다. Eiffel에서는 여러 부모 클래스로부터 상속받을 수 있습니다.
4. Perl: Perl은 다중 상속을 지원하는 스크립트 언어입니다. 여러 부모 클래스로부터 상속받을 수 있으며, 다중 상속의 유연성을 활용하여 다양한 기능을 구현할 수 있습니다.

 

실습 8-10: 2개의 기본 클래스 상속 1

#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;
}

 

실습 8-11: 2개의 기본 클래스 상속 2

#include <iostream>
using std::cout;
using std::endl;
class B1 { //아버지
	double d;
public:
	B1(double dd) { d = dd; }
	double getD() { return d; }
};
class B2 { //어머니
	int i;
public:
	B2(int ii) { i = ii; }
	int getI() { return i; }
};
class D :public B1, public B2 {
	char c;
public:
	D(double dd, int ii, char cc) :B1(dd), B2(ii)
	{
		c = cc;
	}
	void print() {
		cout << "Double : " << getD() << endl;
		cout << "Int : " << getI() << endl;
		cout << "Char : " << c << endl;
	}
};
int main()
{
	D d(1.23, 10, 'H');
	cout << d.getD() << ',' << d.getI() << endl;
	d.print();
	return 0;
}

 

실습 8-12: 여러 개의 기본 클래스를 상속 받을 때, 생성자와 소멸자의실행 순서

#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;
}

▶ 생성자는 순서대로 호출이 외고 소멸자는 역순으로 호출한다.

 

실습 8-13: 이름과 전화번호를 관리(기본클래스 Name, 파생클래스Phone)

#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;
}

class diagram

 

과제 par1.

#include <iostream>
using std::cout;
using std::endl;
using std::string;

class Man {
	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;
	}
};

int main()
{
	//Student kks("김컴소", 20, "C반", "202012000");
	//Teacher hsh("한미소", 40, "전산", "C++프로그래밍");
	//kks.s_show();
	//hsh.t_show();
	return 0;
}

▶ 부모 클래스 완성

self와 this:

 'self' 와 'this'는 프로그래밍에서 객체 지향 프로그래밍(OOP)의 핵심 요소인 인스턴스 메소드에서 현재 인스턴스를 참조하는 키워드

1.Python 'self'

class TestClass:
    def __init__(self, name):
        self.name = name

    def printName(self):
        print(self.name)

test = TestClass('루튼')
test.printName()  # '루튼' 출력

 

2. javaScript 'this'

class TestClass {
    constructor(name) {
        this.name = name;
    }

    printName() {
        console.log(this.name);
    }
}

const test = new TestClass('루튼');
test.printName();  // '루튼' 출력

 

과제 part2.

#include <iostream>
using std::cout;
using std::endl;
using std::string;

class Man {
	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 ban, string hak) : Man(n, a){
		this->ban = ban;
		this->hak = hak;
	}
	void s_show() {
		m_show();
		cout << "반: " << ban << endl;
		cout << "학번: " << hak << endl << endl;
	}
	
};

int main()
{
	/*Student kks("김컴소", 20, "C반", "202012000");
	Teacher hsh("한미소", 40, "전산", "C++프로그래밍");
	kks.s_show();
	hsh.t_show();*/
	return 0;
}

과제 완성

#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 ban, string hak) : Man(n, a){
		this->ban = ban;
		this->hak = hak;
	}
	void s_show() {
		m_show();
		cout << "반: " << ban << endl;
		cout << "학번: " << hak << endl << endl;
	}
	
};

class Teacher :public Man {
	string major;
	string subject;
public:
	Teacher(string n, int a, string major, string subject) :Man(n, a) {
		this->major = major;
		this->subject = subject;
	}
	void t_show() {
		m_show();
		cout << "전공: " << major << endl;
		cout << "담당과목: " << subject << endl;
	}
};
int main()
{
	Student kks("김컴소", 20, "C반", "202012000");
	Teacher hsh("한미소", 40, "전산", "C++프로그래밍");
	kks.s_show();
	hsh.t_show();
	return 0;
}

class diagram

과제 C++ →  python, java

class Man:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def m_show(self):
        print(f"이름: {self.name}")
        print(f"나이: {self.age}")


class Student(Man):
    def __init__(self, name, age, ban, hak):
        super().__init__(name, age)
        self.ban = ban
        self.hak = hak

    def s_show(self):
        self.m_show()
        print(f"반: {self.ban}")
        print(f"학번: {self.hak}\n")


class Teacher(Man):
    def __init__(self, name, age, major, subject):
        super().__init__(name, age)
        self.major = major
        self.subject = subject

    def t_show(self):
        self.m_show()
        print(f"전공: {self.major}")
        print(f"담당과목: {self.subject}")


kks = Student("김컴소", 20, "C반", "202012000")
hsh = Teacher("한미소", 40, "전산", "C++프로그래밍")

kks.s_show()
hsh.t_show()
class Man {
    protected String name;
    protected int age;

    public Man(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void m_show() {
        System.out.println("이름: " + name);
        System.out.println("나이: " + age);
    }
}

class Student extends Man {
    private String ban;
    private String hak;

    public Student(String name, int age, String ban, String hak) {
        super(name, age);
        this.ban = ban;
        this.hak = hak;
    }

    public void s_show() {
        m_show();
        System.out.println("반: " + ban);
        System.out.println("학번: " + hak);
    }
}

class Teacher extends Man {
    private String major;
    private String subject;

    public Teacher(String name, int age, String major, String subject) {
        super(name, age);
        this.major = major;
        this.subject = subject;
    }

    public void t_show() {
        m_show();
        System.out.println("전공: " + major);
        System.out.println("담당과목: " + subject);
    }
}

public class Main {
    public static void main(String[] args) {
        Student kks = new Student("김컴소", 20, "C반", "202012000");
        Teacher hsh = new Teacher("한미소", 40, "전산", "C++프로그래밍");
        kks.s_show();
        hsh.t_show();
    }
}

overriding:가상함수(virtual function)

static


오버로딩(Overloading) vs 오버라이딩(Overriding)

1. 오버로딩(Overloading): 오버로딩은 같은 이름의 메소드가 여러 개 있지만, 매개변수의 타입이나 개수가 다른 경우를 말합니다. 이를 통해 같은 기능을 하는 메소드에 대해 동일한 이름을 사용할 수 있습니다. 매개변수의 타입이나 개수에 따라 자동으로 적절한 메소드를 선택하여 실행합니다.

2. 오버라이딩(Overriding): 오버라이딩은 상위 클래스에서 이미 정의된 메소드를 하위 클래스에서 재정의하여 사용하는 것을 말합니다. 메소드의 이름, 매개변수의 타입 및 개수, 반환 타입이 모두 동일해야 하며, 하위 클래스의 메소드에서 상위 클래스의 메소드를 덮어씁니다. 이를 통해 상속받은 메소드의 기능을 변경하거나 확장할 수 있습니다.

 

오버라이딩: 가상함수 구현

6p

 

실습 9 -6: virtual 있을 때와 없을 때의 차이

#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() { cout <<"Line::draw()\n";}
};
int main() {
	Line line;
	line.print();
	return 0;
}

위 소스 결과

#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() override { 
		cout <<"Line::draw()\n";
	}
};
int main() {
	Line line;
	line.print();
	return 0;
}

▶ 자식쪽에서 override는 써도되고 안써도 된다. 부모쪽에서는 반드시 함수 앞에 virtual을 써야 한다.

위 소스 결과

 

출처: c++ 프로그래밍 강의자료