Sololearn C++ Tutorial 배운 내용 메모: Inheritance & Polymorphism
1. Inheritance
class Mother
{
public:
Mother() {};
void sayHi() {
cout << "Hi";
}
};
class Daughter
{
public:
Daughter() {};
};
아래와 같이 바꿈
class Daughter : public Mother
{
public:
Daughter() {};
};
The Base class is specified using a colon and an access specifier: public means, that all public members of the base class are public in the derived class. In other words, all public members of the Mother class become public members of the Daughter class.
As all public members of the Mother class become public members for the Daughter class, we can create an object of type Daughter and call the sayHi() function of the Mother class for that object
mother = base, daughter = derived 임
2. protected members
* it's a good practice to use public methods to access private class variables.
A protected member variable or function is very similar to a private member, with one difference - it can be accessed in the derived classes
- <Type of Inheritance>
Access specifiers are also used to specify the type of inheritance.
Remember, we used public to inherit the Daughter class:class Daughter: public Mother
private and protected access specifiers can also be used here.
Public Inheritance: public members of the base class become public members of the derived class and protected members of the base class become protected members of the derived class. A base class's private members are never accessible directly from a derived class, but can be accessed through calls to the public and protected members of the base class.
Protected Inheritance: public and protected members of the base class become protected members of the derived class.
Private Inheritance: public and protected members of the base class become private members of the derived class.
Public inheritance is the most commonly used inheritance type.
If no access specifier is used when inheriting classes, the type becomes private by default.
3. Derived Class Constructor & Destructor
When inheriting classes, the base class' constructor and destructor are not inherited. However, they are being called when an object of the derived class is created or deleted.
* 아래 코드에서, 프로그램이 실행되면 객체가 생겼다가 바로 사라지게 된다
class Mother {
public:
Mother()
{
cout <<"Mother ctor"<<endl;
}
~Mother()
{
cout <<"Mother dtor"<<endl;
}
};
int main() {
Mother m;
}
/* Outputs
Mother ctor
Mother dtor
*/
그리고 아래와 같은 경우,
class Daughter: public Mother {
public:
Daughter()
{
cout <<"Daughter ctor"<<endl;
}
~Daughter()
{
cout <<"Daughter dtor"<<endl;
}
};
int main() {
Daughter m;
}
/*Outputs
Mother ctor
Daughter ctor
Daughter dtor
Mother dtor
*/
Note that the base class' constructor is called first, and the derived class' constructor is called next.
When the object is destroyed, the derived class's destructor is called, and then the base class' destructor is called.
You can think of it as the following: The derived class needs its base class in order to work - that is why the base class is set up first
<Summary>
Constructors
The base class constructor is called first.
Destructors
The derived class destructor is called first, and then the base class destructor gets called.
This sequence makes it possible to specify initialization and de-initialization scenarios for your derived classes.
4. Polymorphism
class Enemy {
protected:
int attackPower;
public:
void setAttackPower(int a){
attackPower = a;
}
};
class Ninja: public Enemy {
public:
void attack() {
cout << "Ninja! - "<<attackPower<<endl;
}
};
class Monster: public Enemy {
public:
void attack() {
cout << "Monster! - "<<attackPower<<endl;
}
};
int main() {
Ninja n;
Monster m;
Enemy *e1 = &n;
Enemy *e2 = &m;
e1->setAttackPower(20);
e2->setAttackPower(80);
n.attack();
m.attack();
}
/* Output:
Ninja! - 20
Monster! - 80
*/
위 코드에서, We would have achieved the same result by calling the functions directly on the objects. However, it's faster and more efficient to use pointers. Also, the pointer demonstrates, that you can use the Enemy pointer without actually knowing that it contains an object of the subclass.
5. Virtual function
To be able to call the corresponding attack() function for each of the derived classes using Enemy pointers, we need to declare the base class function as virtual. Defining a virtual function in the base class, with a corresponding version in a derived class, allows polymorphism to use Enemy pointers to call the derived classes' functions.
As the attack() function is declared virtual, it works like a template, telling that the derived class might have an attack() function of its own.
If a function in the base class is virtual, the function's implementation in the derived class is called according to the actual type of the object referred to, regardless of the declared type of the pointer.
A class that declares or inherits a virtual function is called a polymorphic class.
class Enemy {
public:
virtual void attack() {
cout << "Enemy!"<<endl;
}
};
class Ninja: public Enemy {
public:
void attack() {
cout << "Ninja!"<<endl;
}
};
class Monster: public Enemy {
public:
void attack() {
cout << "Monster!"<<endl;
}
};
int main() {
Ninja n;
Monster m;
Enemy e;
Enemy *e1 = &n;
Enemy *e2 = &m;
Enemy *e3 = &e;
e1->attack();
// Outputs "Ninja!"
e2->attack();
// Outputs "Monster!"
e3->attack();
// Outputs "Enemy!"
}
When a virtual function is called via base class pointer, it calls those class' function to which the base class pointer points.
The virtual member functions without definition are known as pure virtual functions. They basically specify that the derived classes define that function on their own.
The syntax is to replace their definition by =0 (an equal sign and a zero):
class Enemy {
public:
virtual void attack() = 0;
};
//The = 0 tells the compiler that the function has no body.
A pure virtual function basically defines, that the derived classes will have that function defined on their own.
Every derived class inheriting from a class with a pure virtual function must override that function. If the pure virtual function is not overridden in the derived class, the code fails to compile and results in an error when you try to instantiate an object of the derived class.
You cannot create objects of the base class with a pure virtual function. Running the following code will return an error:
Enemy e; // Error
These classes are called abstract. They are classes that can only be used as base classes, and thus are allowed to have pure virtual functions. -> 퓨어 가상 함수를 가진 클래스를 추상이라고 한다는 것.
You might think that an abstract base class is useless, but it isn't. It can be used to create pointers and take advantage of all its polymorphic abilities. For example, you could write:
Ninja n;
Monster m;
Enemy *e1 = &n;
Enemy *e2 = &m;
e1->attack();
e2->attack();
In this example, objects of different but related types are referred to using a unique type of pointer (Enemy*), and the proper member function is called every time, just because they are virtual.