가상소멸자, 다중상속, 추상클래스, 인터페이스, 캐스팅
비 가상 소멸자
//Animal.h
class Animal
{
public:
~Animal();
private:
int mAge;
};
//Cat.h
class Cat : public Animal
{
public:
~Cat();
private:
char* mName;
};
//ex1 Cat
Cat* myCat = new Cat(2, "Coco"); //Cat.h 의 소멸자 호출 다음 부모 소멸자 호출 이상없음
delete myCat;
//ex2 업캐스팅 Cat
Animal* yourCat = new Cat(5, "Mocha"); //현재의 데이터 형이 Animal클래스이기때문에
delete yourCat; //바로 Animal class 소멸자만 호출.
//자식클래스 소멸자 호출안되므로 mName 메모리누수
가상 소멸자
//Animal.h
class Animal
{
public:
virtual ~Animal();
private:
int mAge;
};
//Cat.h
class Cat : public Animal
{
public:
virtual ~Cat();//여기는 virtual 키워드 생략해도됨. 혹시나 Cat 을 다시 상속받을수도있으니..
private:
char* mName;
};
//Cat.cpp
Cat::~Cat()
{
delete mName;
}
- 모든 소멸자에는 언제나 virtual 키워드를 넣을것.
-
because. 협업시에 내가만든 클래스를 누군가 상속해서 쓸 수도 있는데 그럴경우 일일이 컨트롤할 수 없기때문에..
다형성
-
업캐스팅으로 다양한 클래스들을 하나의 배열로 컨트롤하는데에 유용함
다중 상속
//Animal.h
class Animal
{
};
//Tiger.h
class Tiger : virtual public Animal
{
};
//Lion.h
class Lion : virtual public Animal
{
};
//Liger.h
class Liger : public Tiger, public Lion
{
};
//가상 베이스클래스로 상속받으면 해결 가능하지만 한번에 이런 구조를 만들지 않는이상 해결하기 어려운점이 있음.
//해결책은 인터페이스를 통해서 해결가능.
추상(abstract) 클래스
- 순수 가상함수를 가지고 있는 베이스 클래스를 추상클래스라 함.
- 추상 클래스에서 개체를 만들 수 없음
- 추상 클래스를 포인터나 참조 형으로는 사용가능
//Animal.h
class Animal
{
public:
virtual ~Animal();
virtual void Speak() = 0;//순수 가상함수 : 구현체가 없는 멤버함수, 파생클래스가 구현해야함.
private:
int mAge;
};
//Cat.h
class Cat : public Animal
{
public:
~Cat();
void Speak();
private:
char* mName;
};
인터페이스
- c++은 자체적으로 인터페이스를 지원하지않음
- 순수 추상 클래스를 사용해서 Java의 인터페이스 흉내
- 순수 가상 함수만 가짐
- 멤버 변수는 없음//회사에따라서 멤버변수 안겹치게 선언하는곳도있음.
// IFlyable.h
class IFlyable
{
public:
virtual void Fly() = 0;
};
//IWalkable.h
class IWalkable
{
public:
virtual void Walk() = 0;
};
class Bat : public IFlyable, public IWalkable
{
public:
void Fly();
void Walk();
};
class Cat : public IWalkable
{
public:
void Walk();
};
명시적(Explicit) 캐스팅
- c++ 캐스팅
- static_cast
- const_cast
- dynamic_cast
- reinterpret_cast
static_cast
Animal* myPet = new Cat(2, "Coco");
Cat* myCat = static_cast<Cat*>(myPet);
Dog* myDog = static_cast<Dog*>(myPet); //컴파일되지만 위험, Dog 클래스 멤버를
myDog->GetDogHouseName(); //가지고있지 않기때문에 크래시가 날 수 있다.
//Animal.h
class Animal
{
public:
~Animal();
private:
int mAge;
};
//Cat.h
class Cat : public Animal
{
public:
~Cat();
private:
char* mName;
};
//ex1 Cat
Cat* myCat = new Cat(2, "Coco"); //Cat.h 의 소멸자 호출 다음 부모 소멸자 호출 이상없음
delete myCat;
//ex2 업캐스팅 Cat
Animal* yourCat = new Cat(5, "Mocha"); //현재의 데이터 형이 Animal클래스이기때문에
delete yourCat; //바로 Animal class 소멸자만 호출.
//자식클래스 소멸자 호출안되므로 mName 메모리누수
//Animal.h
class Animal
{
public:
virtual ~Animal();
private:
int mAge;
};
//Cat.h
class Cat : public Animal
{
public:
virtual ~Cat();//여기는 virtual 키워드 생략해도됨. 혹시나 Cat 을 다시 상속받을수도있으니..
private:
char* mName;
};
//Cat.cpp
Cat::~Cat()
{
delete mName;
}
-
because. 협업시에 내가만든 클래스를 누군가 상속해서 쓸 수도 있는데 그럴경우 일일이 컨트롤할 수 없기때문에..
다형성
-
업캐스팅으로 다양한 클래스들을 하나의 배열로 컨트롤하는데에 유용함
//Animal.h
class Animal
{
};
//Tiger.h
class Tiger : virtual public Animal
{
};
//Lion.h
class Lion : virtual public Animal
{
};
//Liger.h
class Liger : public Tiger, public Lion
{
};
//가상 베이스클래스로 상속받으면 해결 가능하지만 한번에 이런 구조를 만들지 않는이상 해결하기 어려운점이 있음.
//해결책은 인터페이스를 통해서 해결가능.
추상(abstract) 클래스
- 순수 가상함수를 가지고 있는 베이스 클래스를 추상클래스라 함.
- 추상 클래스에서 개체를 만들 수 없음
- 추상 클래스를 포인터나 참조 형으로는 사용가능
//Animal.h
class Animal
{
public:
virtual ~Animal();
virtual void Speak() = 0;//순수 가상함수 : 구현체가 없는 멤버함수, 파생클래스가 구현해야함.
private:
int mAge;
};
//Cat.h
class Cat : public Animal
{
public:
~Cat();
void Speak();
private:
char* mName;
};
인터페이스
- c++은 자체적으로 인터페이스를 지원하지않음
- 순수 추상 클래스를 사용해서 Java의 인터페이스 흉내
- 순수 가상 함수만 가짐
- 멤버 변수는 없음//회사에따라서 멤버변수 안겹치게 선언하는곳도있음.
// IFlyable.h
class IFlyable
{
public:
virtual void Fly() = 0;
};
//IWalkable.h
class IWalkable
{
public:
virtual void Walk() = 0;
};
class Bat : public IFlyable, public IWalkable
{
public:
void Fly();
void Walk();
};
class Cat : public IWalkable
{
public:
void Walk();
};
명시적(Explicit) 캐스팅
- c++ 캐스팅
- static_cast
- const_cast
- dynamic_cast
- reinterpret_cast
static_cast
Animal* myPet = new Cat(2, "Coco");
Cat* myCat = static_cast<Cat*>(myPet);
Dog* myDog = static_cast<Dog*>(myPet); //컴파일되지만 위험, Dog 클래스 멤버를
myDog->GetDogHouseName(); //가지고있지 않기때문에 크래시가 날 수 있다.
- 추상 클래스에서 개체를 만들 수 없음
- 추상 클래스를 포인터나 참조 형으로는 사용가능
//Animal.h
class Animal
{
public:
virtual ~Animal();
virtual void Speak() = 0;//순수 가상함수 : 구현체가 없는 멤버함수, 파생클래스가 구현해야함.
private:
int mAge;
};
//Cat.h
class Cat : public Animal
{
public:
~Cat();
void Speak();
private:
char* mName;
};
- c++은 자체적으로 인터페이스를 지원하지않음
- 순수 추상 클래스를 사용해서 Java의 인터페이스 흉내
- 순수 가상 함수만 가짐
- 멤버 변수는 없음//회사에따라서 멤버변수 안겹치게 선언하는곳도있음.
// IFlyable.h
class IFlyable
{
public:
virtual void Fly() = 0;
};
//IWalkable.h
class IWalkable
{
public:
virtual void Walk() = 0;
};
class Bat : public IFlyable, public IWalkable
{
public:
void Fly();
void Walk();
};
class Cat : public IWalkable
{
public:
void Walk();
};
명시적(Explicit) 캐스팅
- c++ 캐스팅
- static_cast
- const_cast
- dynamic_cast
- reinterpret_cast
static_cast
Animal* myPet = new Cat(2, "Coco");
Cat* myCat = static_cast<Cat*>(myPet);
Dog* myDog = static_cast<Dog*>(myPet); //컴파일되지만 위험, Dog 클래스 멤버를
myDog->GetDogHouseName(); //가지고있지 않기때문에 크래시가 날 수 있다.
- static_cast
- const_cast
- dynamic_cast
- reinterpret_cast
Animal* myPet = new Cat(2, "Coco");
Cat* myCat = static_cast<Cat*>(myPet);
Dog* myDog = static_cast<Dog*>(myPet); //컴파일되지만 위험, Dog 클래스 멤버를
myDog->GetDogHouseName(); //가지고있지 않기때문에 크래시가 날 수 있다.
for example(static_cast cat to dog)
//animal.cpp
#include "Animal.h"
namespace samples
{
Animal::Animal(int age)
: mAge(age)
{
}
}
//cat.cpp
#include <iostream>
#include "Cat2.h"
namespace samples
{
const char* Cat2::mAnimalType = "Cat";
Cat2::Cat2(int age, const char* name)
: mAge(age)
{
mName = new char[strlen(name) + 1];
memcpy(mName, name, strlen(name) + 1);
}
Cat2::~Cat2()
{
delete[] mName;
}
// static function
const char* Cat2::GetType()
{
return mAnimalType;
}
}
//dog.cpp
#include <cstring>
#include "Dog.h"
namespace samples
{
Dog::Dog(int age, const char* address)
: Animal(age)
{
mHomeAddress = new char[strlen(address) + 1];
memcpy(mHomeAddress, address, strlen(address) + 1);
}
Dog::~Dog()
{
delete[] mHomeAddress;
}
const char* Dog::GetAddress() const
{
return mHomeAddress;
}
}
//static casting ex
#include <iostream>
#include "Animal.h"
#include "Cat.h"
#include "Dog.h"
#include "ObjectPointerCastingExample.h"
using namespace std;
namespace samples
{
void ObjectPointerCastingExample()
{
Animal* pet1 = new Cat(2, "Lulu");
Animal* pet2 = new Dog(2, "Burnaby");
Cat* cat = static_cast<Cat*>(pet1);
Dog* dog1 = static_cast<Dog*>(pet2);
Dog* dog2 = static_cast<Dog*>(pet1);//이부분 cat to dog static casting
cout << "cat's name : " << cat->GetName() << endl;
cout << "dog1's address :" << dog1->GetAddress() << endl;
// prints cat's name instead
cout << "dog2's address : " << dog2->GetAddress() << endl;
//함수 리스트 테이블에서 상대적 위치가 같기때문에 이 함수들은 4바이트만큼 떨어진 곳에 있는
//const char* 멤버 변수를 반환 즉 두 클래스의 변수 접근 위치가 같은 형태였기때문에 접근가능
delete pet1;
delete pet2;
}
}
reinterpret_cast
비트패턴은 바꾸지않으나 컴파일러가 해석하는 데이터형이 바뀜.
reinterpret_cast 사용법
const_cast
void WriteLine(char* ptr);//뭔가 별로인 외부 라이브러리
void MyWriteLine(const char* ptr) //우리프로그램
{
WriteLine(const_cast<char*>(ptr));
}
//써드파티 라이브러리가 const를 제대로 사용하지 않을때
dynamic_cast
RTTI가 꺼져있다면 static_cast 와 똑같이 작동함.
보통 c++ 프로젝트에서는 RTTI를 끄는것이 보통.(성능때문..)
캐스팅 규칙
- 기본적으로 static_cast 를 쓸 것
- reinterpret_cast<Cat> 대신 static_cast<Cat>
- 만약 Cat 이 Animal 이 아니라면 컴파일러가 에러를 뱉음.
- reinterpret_cast<Cat> 대신 static_cast<Cat>
- reinterpret_cast를 쓸 것
- 포인터와 비포인터 사이의 변환
- 정말 해야될 때가 있음(데이터직렬화)
- 서로 연관이 없는 포인터 사이의 변환은 그 데이터형이 맞다고 정말 확실할 때만 할것
- 포인터와 비포인터 사이의 변환
- 내가 변경 권한이 없는 외부 라이브러리를 호출할 때만 const_cast를 쓸 것
Author And Source
이 문제에 관하여(가상소멸자, 다중상속, 추상클래스, 인터페이스, 캐스팅), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jaykay/가상소멸자-다중상속-추상클래스-인터페이스-캐스팅저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)