저는 장식 자 패턴이 작동하는 방식을 이해하려고 노력하고 있으며, 필요한만큼 "늘릴 수"있습니다. this 예제 다음에 XYZ 클래스를 확장했습니다. 파생 클래스 "KLM"(XYZ에서)장식 자 인스턴스화에 대한 C++ dynamic_cast가 실패합니다.
특히 데코레이터 패턴이 있더라도 파생 데코레이터 클래스 "KLM"은 기본 클래스 "XYZ"에 표시되지 않는 일부 기능을 가지고 있습니다. "D", "I"또는 "A". 일반적으로 내가
I * inKLM = new L(new M(new K(new A)));
같은 객체를 생성 할 때이 나를 K::doVirtR()
, L :: doVirtS()와 M :: doVirtT() 함수에 액세스 할 수없는 것입니다 그래서
(아래 코드 참조). 이들에 액세스하려면 각각 "KLM"클래스에 dynamic_cast
을 사용하여 inKLM 포인터를 다운 캐스팅해야합니다.
문제는 위의 표현에서 가장 왼쪽에있는 new
에 대해서만 관리 할 수 있다는 것입니다. 나는 다이나믹 캐스팅이 작동하도록 다형성을 유지할 필요가 있음을 읽었으므로 모든 기능에 가상 소멸자를 갖기 위해 노력했다. 여전히 "외부"new
작업 (이 경우 클래스 "L"의 개체) 이외의 작업을 수행하려면 동적 캐스트를 가져올 수 없습니다.
이 코드를 참조하십시오. dynamic_casting에서 "LinKLM"뿐만 아니라 "MinKLM"및 "KinKLM"을 성공적으로 만들 수있는 방법은 무엇입니까?
#include <iostream>
#include <list>
using namespace std;
class D; //decorator base
struct I { //interface (for both Base and DecoratorBase
I(){
cout << "\n| I::ctor ";
}
virtual ~I(){
cout << "I::dtor |" ;
}
virtual void do_it() = 0;
virtual void regDecorator(D* decorator) = 0;
virtual void train() = 0;
virtual void et() = 0;
};
class D: public I { //DecoratorBase : has same-named fns as Base (must be exported on I) and calls upon them.
public:
D(I * inner) : m_wrappee(inner) {
cout << "D::ctor ";
regDecorator(this);
}
virtual ~D() {
cout << "D::dtor ";
delete m_wrappee;
}
void do_it() {
m_wrappee->do_it();
}
virtual void et() {
cout << "filling in for lack of et() in derived class\n";
} //almost pure virtual, just not implemented in all derived classes
void train(){
m_wrappee->train();
}
private:
void regDecorator(D* decorator){
m_wrappee->regDecorator(decorator);
}
I * m_wrappee;
};
class A: public I { //Base has all the basic functionality
public:
A() {
cout << "A::ctor " ;
decList.clear();
}
~A() {
cout << "A::dtor |" ;
}
void do_it() {
cout << 'A';
}
void train(){
et();
}
void regDecorator(D* decorator)
{
if (decorator) {
cout << "reg=" << decorator << " ";
decList.push_back(decorator);
}
else
cout << "dec is null!" <<endl;
}
private:
void et()
{
//size_t counter=0;
list<D*>::iterator it;
for(it=decList.begin(); it != decList.end(); it++)
{
//if ((*it)->et())
(*it)->et();
//else
// cout << "couldnt et cnt=" << counter << endl;
//counter++;
}
}
std::list<D*> decList;
};
class X: public D { //DerivedDecoratorX ..
public:
X(I *core): D(core){
cout << "X::ctor ";
}
virtual ~X() {
cout << "X::dtor ";
}
void do_it() {
D::do_it();
cout << 'X';
}
void doX() {
cout << "doX" << endl;
}
protected:
virtual void doVirtR() = 0;
private:
void et(){
cout << "X::et" <<endl;
}
};
class K: public X {
public:
K(I * core):X(core) {
cout << "K::ctor " ;
}
virtual ~K() {
cout << "K::dtor ";
}
void doVirtR(){
cout << "doVirtK" <<endl;
}
};
class Y: public D {
public:
Y(I *core): D(core){
cout << "Y::ctor ";
}
virtual ~Y() {
cout << "Y::dtor ";
}
/*void et(){
cout << "Y::et" <<endl;
}*/
void do_it() {
D::do_it();
cout << 'Y';
}
void doY() {
cout << "doY" << endl;
}
protected:
virtual void doVirtS() = 0;
};
class L: public Y{
public:
L(I * core):Y(core) {
cout << "L::ctor ";
}
virtual ~L() {
cout << "L::dtor ";
}
void doVirtS(){
cout << "doVirtL" <<endl;
}
};
class Z: public D {
public:
Z(I *core): D(core){
cout << "Z::ctor ";
}
virtual ~Z() {
cout << "Z::dtor ";
}
void et(){
cout << "Z::et" <<endl;
}
void do_it() {
D::do_it();
cout << 'Z';
}
void doZ() {
cout << "doZ" << endl;
}
virtual void doVirtT() = 0;
};
class M: public Z{
public:
M(I * core):Z(core) { //must add D(core) here explicitly because of virtual inheritance in M's base class (Z).
cout << "M::ctor " ;
}
virtual ~M() {
cout << "M::dtor ";
}
void doVirtT(){
cout << "doVirtM" <<endl;
}
};
int main(void) //testing dynamic casting
{
I * inKLM = new L(new M(new K(new A)));
L * LinKLM = dynamic_cast<L *>(inKLM);
M * MinKLM = dynamic_cast<M *>(inKLM);
K * KinKLM = dynamic_cast<K *>(inKLM);
cout << endl;
if (! MinKLM) cout << "null MinKLM!" << endl;
if (! LinKLM) cout << "null LinKLM!" << endl;
if (! KinKLM) cout << "null KinKLM!" << endl;
//KinKLM->doVirtR();
//LinKLM->doVirtS();
//MinKLM->doVirtT();
//LinKLM->D::train();
//KinKLM->do_it();
//MinKLM->doZ();
delete inKLM;
cout << endl;
return 0;
}
생성자가 ptrs를 기본 클래스로 사용하는 이유는 무엇입니까? 예를 들어, 'I * inKLM = new L (새 M (새 K));'은 가능한 한 많이 유출 된 것처럼 보입니다. –
@BenjaminBannier 제가 알기에 이것은 장식 자 패턴의 핵심입니다. – nass