프로그래밍 언어 중에는 다중 상속을 지원하는 언어들이 있습니다. 파이썬도 그 중 하나입니다. 다중 상속을 이용하면 여러 클래스의 특성을 한 번에 상속받을 수 있습니다. 아래에 파이썬에서 다중 상속을 사용하는 예시 코드를 작성해 봅니다:
# 클래스 A 정의
class A:
def methodA(self):
return "methodA from Class A"
# 클래스 B 정의
class B:
def methodB(self):
return "methodB from Class B"
# 다중 상속을 이용하여 클래스 A와 B의 메소드를 모두 가진 클래스 C 정의
class C(A, B):
pass
# 클래스 C의 인스턴스 생성
c = C()
# 메소드 실행
print(c.methodA()) # 출력: methodA from Class A
print(c.methodB()) # 출력: methodB from Class B
위의 코드에서 클래스 C는 클래스 A와 B를 다중 상속 받았습니다. 따라서 클래스 C의 인스턴스 c는 A의 methodA와 B의 methodB를 모두 호출할 수 있습니다. 이처럼 다중 상속은 한 클래스가 여러 클래스의 특성을 동시에 가질 수 있게 해줍니다. 그러나 다중 상속은 복잡성을 증가시킬 수 있으므로 신중하게 사용해야 합니다.
#include
using std::string;
using std::cout;
using std::endl;
class Man {
std::string name;
int age;
public:
Man(std::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;
}
부모 클래스 작성;;
네, 물론입니다. 오버로딩(Overloading)과 오버라이딩(Overriding)은 모두 프로그래밍에서 매우 중요한 개념이며, 이 둘은 비슷해 보이지만 기능과 용도가 많이 다릅니다.
예를 들어, 덧셈 함수를 생각해보면 다음과 같이 표현할 수 있습니다.
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
이는 오버로딩의 예로, 'add'라는 같은 이름의 함수를 사용하지만 매개변수의 유형이 다릅니다.
예를 들어, 동물 클래스와 그를 상속받은 개 클래스를 생각해보면 다음과 같이 표현할 수 있습니다.
class Animal {
void sound() {
print("This animal makes a sound");
}
}
class Dog extends Animal {
void sound() {
print("The dog barks");
}
}
이는 오버라이딩의 예로, 'sound'라는 같은 이름의 메서드를 가지지만 개 클래스에서 해당 메서드를 재정의하여 개의 소리를 출력하도록 하였습니다.
이렇게 보시면, 오버로딩은 같은 이름의 메서드를 매개변수의 유형과 개수를 바꿔 여러 번 선언하는 것이고, 오버라이딩은 상속 관계의 클래스에서 부모 클래스의 메서드를 자식 클래스에서 재정의하는 것임을 알 수 있습니다.
override 는 자식쪽에서는 사용해도 되고 안 해도 된다
C++에서 virtual
과 override
키워드를 사용하는 예제를 드리겠습니다. 이 두 키워드는 상속과 관련된 특성에서 주로 사용되며, 클래스의 멤버 함수를 재정의하는 데 사용됩니다.
#include<iostream>
using namespace std;
class Base {
public:
// 기본 클래스에서 가상 함수를 선언합니다.
// 이 함수는 파생 클래스에서 재정의 될 수 있습니다.
virtual void print() {
cout << "Base class print function." << endl;
}
};
class Derived : public Base {
public:
// 파생 클래스에서 기본 클래스의 함수를 재정의합니다.
// override 키워드는 선택 사항이지만, 컴파일러에게 이 함수가 부모 클래스의 함수를 재정의한다는 것을 명시적으로 알려줍니다.
void print() override {
cout << "Derived class print function." << endl;
}
};
int main() {
Base* base_ptr;
Derived derived_obj;
// 기본 클래스 포인터를 파생 클래스 객체에 연결합니다.
base_ptr = &derived_obj;
// 이제 파생 클래스의 print 함수가 호출됩니다.
base_ptr->print();
return 0;
}
이 코드는 Base
라는 기본 클래스와 Derived
라는 파생 클래스가 있습니다. Base
클래스에는 print
라는 가상 함수(virtual
함수)가 있습니다. 가상 함수란 파생 클래스에서 재정의될 수 있는 멤버 함수를 말합니다. 이 경우, Derived
클래스에서 print
함수를 재정의하였습니다.
override
키워드는 이 함수가 기본 클래스의 함수를 재정의하고 있다는 것을 컴파일러에게 명시적으로 알려줍니다. 이 키워드가 없더라도 함수 오버라이딩은 가능하지만, override
키워드를 사용하면 코드의 명확성을 높이고 잠재적인 오류를 미리 방지할 수 있습니다.
마지막으로, main
함수에서 기본 클래스 포인터를 사용하여 파생 클래스의 객체를 참조하고, print
함수를 호출하면 파생 클래스의 print
함수가 실행됩니다. 이는 가상 함수의 동적 바인딩 특성 때문입니다. 이 특성 때문에 실행 시간에 적절한 함수 버전이 선택됩니다.