가상 소멸자

상속구조에서 생성자는 자식클래스는 자식클래스 생성자를 사용한다.
하지만 소멸자는 가상 소멸자를 사용하는게 좋다.

소멸자를 생성하지 않으면 자식소멸자,부모소멸자 순으로 실행된다.

하지만 부모클래스에 자식클래스를 대입한후 부모클래스를 delete하면 자식클래스의 소멸자가 실행안돼
메모리 릭이 생긴다.

부모클래스 소멸자에 virtual 을 해주면 자식 클래스의 소멸자도 실행시켜준다.

 

#include <iostream>

using namespace std;

class Base
{
public:
	virtual ~Base() {
		cout << "~Base()" << endl;
	}

};

class Derived : public Base
{
private:
	int *m_array;

public:
	Derived(int len)
	{
		m_array = new int[len];
	}

	~Derived() {
		cout << "~Derived" << endl;
		delete[] m_array;
	}

};
int main()
{
	Derived *d = new Derived(5);
	Base *b = d;

	delete b;

	return 0;
}

'개발 소발 > 개발 C++(기초)' 카테고리의 다른 글

c++ vitual,가상함수  (0) 2019.09.30
c++ 정적,동적바인딩  (0) 2019.09.30
c++ override,final,공변 반환값  (0) 2019.09.23
c++ 가상함수와 다형성  (0) 2019.09.23
c++ 다형성의 기본개념  (0) 2019.09.23

override,final,공변 반환값

공변 반환형
Covariant

다형성쓸때 유용하게 쓸 수 있다.

오버로딩(파라미터가 다름)을 하면 상속이 적용안된다.

메소드명 뒤 override 사용하기!

오버라이드 할려했는데 실수로 오버로딩할 수 있다.

그걸 체크하려면 메소드 명 뒤에 override를 붙여준다.

class A {
virtual void printOverride(int x)  const{ cout << "A" << endl; }
}

class B : public A{
void printOverride(int x)  const override { cout << "B" << endl; }
}



메소드명 뒤 final 사용하기!

하위 클래스가 override하지 않게 하고싶을 수 있다.

상위 클래스 메소드명 뒤에 final을 붙여주면 오버라이드 할 수 없다.

virtual void printFinal(int x) final { cout << "A" << endl; }




반환값이 다르면 오버라이딩 안되지만

반환값이 부모자식관계면 오버라이딩이 된다.

오버라이딩은 되지만 부모 인스턴스에 자식을 대입하면 부모클래스가 출력된다.

class A{
	virtual A *getThis() { return this; }
};
class B : public A{
	B *getThis() { return this; }
};

 

코드 내용

#include <iostream>

using namespace std;

class A
{
public:
	virtual void printOverride(int x)  const{ cout << "A" << endl; }
	
	//final을 붙이면 오버라이드 할 수 없다.
	virtual void printFinal(int x) final { cout << "A" << endl; }
	
	void print() { cout << "A" << endl; }
	virtual A *getThis() { return this; }
};

class B : public A
{
public:
	void printOverride(int x)  const override { cout << "B" << endl; }
	
	//에러난다.
	//virtual void printFinal(int x) { cout << "B " << endl; }
	
	void print() { cout << "B" << endl; }
	B *getThis() { return this; }
};
int main() {

	A a;
	B b;
	
	A &ref = b;
	b.getThis()->print();
	ref.getThis()->print();

	cout << typeid(b.getThis()).name() << endl;
	//부모클래스가 출력된다.
	cout << typeid(ref.getThis()).name() << endl;
	return 0;
}

'개발 소발 > 개발 C++(기초)' 카테고리의 다른 글

c++ 정적,동적바인딩  (0) 2019.09.30
c++ 가상소멸자  (0) 2019.09.23
c++ 가상함수와 다형성  (0) 2019.09.23
c++ 다형성의 기본개념  (0) 2019.09.23
c++ 상속받은 함수를 오버라이딩하기  (0) 2019.08.30

가상함수와 다형성

다형성은 상속구조와 virtual을 사용한다.

virtual을 붙인 함수는 가상함수라고 부른다.

A,B,C,D 4가지 클래스를 생성하고 상속을 해보았다.

A의 포인터,Reference를 사용하며 A클래스의 메소드에 virtual을 사용하게 되면

자식클래스들은 모두 영향을 받는다.

즉, 가장 상위클래스의 virtual이 되면 밑에 클래스 모든 메소드도 virtual로 인식되게 된다.

상위클래스에만 있어도 되지만 형식적으로 자식클래스에도 virtual을 사용해놓는다.

오버라이딩한걸 인식하기 위해서 이다.

virtual 키워드는 스택처럼 차곡차곡 쌓는게 아닌 테이블을 찾는 과정이다.

찾아가는 과정이 있기에 속도가 느리다.

 

#include <iostream>
#include <string>

using namespace std;
class A
{
public:
	virtual void print() {
		cout << "A" << endl;
	}
};

class B : public A
{
public:
	void print() {
		cout << "B" << endl;
	}
};

class C : public B
{
public:
	void print() {
		cout << "C" << endl;
	}
};
class D : public C
{
public:
	void print() {
		cout << "D" << endl;
	}
};

int main()
{
	A a;
	B b;
	C c;
	D d;

	//포인터도 사용가능
	//가장 상위클래스에 virtual이 선언되어 있으면 모두 영향 받는다.
	A &ref = c;
	ref.print();

	return 0; 
}

'개발 소발 > 개발 C++(기초)' 카테고리의 다른 글

c++ 가상소멸자  (0) 2019.09.23
c++ override,final,공변 반환값  (0) 2019.09.23
c++ 다형성의 기본개념  (0) 2019.09.23
c++ 상속받은 함수를 오버라이딩하기  (0) 2019.08.30
c++ 상속과 접근지정자  (0) 2019.08.30

다형성의 기본개념

자식클래스의 객체에 부모 클래스의 포인터를 사용한다면?

 

부모클래스 *포인터 = 자식클래스;


위처럼 하면 부모클래스의 메소드가 실행된다. 

하지만 virtual을 메소드에 붙여주면 자식 메소드가 실행되게 된다.

	virtual void speak() const
	{
		cout << m_name << " ??? " << endl; 
	}


자식클래스에 메소드가 없으면 부모클래스가 실행된다.

이걸 다형성이라고 부른다.

 

#include <iostream>
#include <string>

using namespace std;

class Animal
{
protected:
	string m_name;

public:
	Animal(string name)
		: m_name(name) {

	}

	string getName() { return m_name; }

	virtual void speak() const
	{
		cout << m_name << " ??? " << endl; 
	}
};

class Cat :public Animal 
{
public:
	Cat(string name)
		:Animal(name) {

	}

	void speak() const
	{
		cout << m_name << " Meow " << endl;
	}
};


class Dog :public Animal
{
public:
	Dog(string name)
		:Animal(name) {

	}

	void speak() const
	{
		cout << m_name << " Woof " << endl;
	}
};
int main() {

	Animal a("Animal");
	Dog d("Dog");
	Cat c("Cat");

	//자식클래스를 부모클래스의 포인터로 캐스팅해서 사용하면
	//자신이 부모클래스인줄 알고 작동한다.
	a.speak();
	d.speak();
	c.speak();

	Animal *a1 = &d;
	Animal *a2 = &c;


	//활용하는 경우
	Cat cats[] = { Cat("cat1"),Cat("cat2"), Cat("cat3"), Cat("cat4"), Cat("cat5") };
	Dog dogs[] = { Dog("dog1"), Dog("dog2") };
	//위에껄 다 확인해볼려면 for문을 사용해야한다.

	Animal *my_animals[] = { &cats[0],&cats[1], &cats[2], &cats[3], &cats[4], &dogs[0], &dogs[1] };

	//부모클래스의 메소드가 실행된다.
	//virtual 을 붙이면 자식클래스인것처럼 실행한다.
	//이런 성질을 다형성이라고 한다.
	for (int i = 0; i < 7; i++)
		my_animals[i]->speak();


	return 0;
}

+ Recent posts