저는 거의 동일하지만 아주 비슷하지 않은 한 쌍의 기본/파생 클래스가 있습니다.거의 동일한 base> 파생 된 클래스의 쌍에서 코드 중복을 피하십시오.
는 단순히 Base2 > Derived2
을 만들 Base1 > Derived1
의 모든 코드를 복사 할 수 있지만, 추한 것, 두 번 거의 모든 수정을 요구한다.
질문 : 코드 중복을 피하기 위해 두 쌍 사이에 가능한 한 많은 코드를 공유 할 수 있습니까?
실제 문제의 대부분의 기능을 가진 작은 장난감 예제를 만들려고했습니다. 나는 D1
과 D2
의 인터페이스의 동일한 부분에 중복되는 코드가 없도록하고 싶다. 실제 문제를 더보고 싶다면 질문 끝으로 스크롤하십시오.
#include <iostream>
using namespace std;
//////////// 1st PAIR ////////////
class B1 {
protected:
string name;
public:
B1() : name("B1") { } // constructors are different between B1 and B2
void speak() { cout << name << endl; } // identical between B1 and B2
};
template<typename T>
class D1 : public B1 {
T x; // identical between D1 and D2
public:
D1(const T &a) { x = a + name.size(); } // refers to base class member
int getX() { return x; } // identical between D1 and D2
int nameLength() { return name.size(); } // accesses member of B, identical between D1 and D2
// differences between D1 and D2 follow:
int add(int i, int j) { return i+j; } // different signature between D1 and D2
void more() {} // not present in D1
};
//////////// 2nd PAIR ////////////
class B2 {
protected:
string name;
public:
B2() : name("B2") { }
void speak() { cout << name << endl; }
};
template<typename T>
class D2 : public B2 {
T x; // identical between D1 and D2
public:
D2(const T &a) { x = a + name.size(); }
int getX() { return x; } // identical between D1 and D2
int nameLength() { return name.size(); } // accesses member of B, identical between D1 and D2
int add(int i, int j, int k) { return i+j+k; } // different signature between D1 and D2
};
// this is just to test that the program compiles and works
int main() {
D1<int> d1(5);
D2<long> d2(6l);
cout << d1.getX();
cout << d1.nameLength();
return 0;
}
은 B1
및 B2
의 인터페이스는 그 클래스 BInterface
에서 상속하여 공유 할 수 있습니다.
추가 기본 클래스 DInterface
을 통해 D1
및 D2
과 동일한 작업을 수행 할 수 있도록 다중 상속을 사용하는 것이 좋습니다. 또한, 흥미로운 반복 템플릿 패턴을 사용하여이 추가 기본 클래스가 D1
및 D2
의 멤버에 액세스 할 수 있도록하는 것이 좋습니다. 이것에 대한 나의 시도는 다음과 같다. 조금 복잡하다는 것을 알았습니다.이 방법이 합리적인 방법인지 그리고 동일한 방법을 사용하는 것이 더 나은지 알고 싶습니다.
#include <iostream>
using namespace std;
//////////// COMMON INTERFACES ////////////
class BInterface {
protected:
string name;
BInterface(const string &n) : name(n) { }
public:
void speak() { cout << name << endl; }
};
template<typename D>
class DInterface {
private:
D &derived() { return *static_cast<D *>(this); }
protected:
DInterface() {}
public:
int getX() { return derived().x; }
int nameLength() { return derived().name.size(); }
};
//////////// 1st PAIR ////////////
class B1 : public BInterface {
public:
B1() : BInterface("B1") { } // constructors are different between B1 and B2
};
template<typename T>
class D1 : public B1, public DInterface< D1<T> > {
friend class DInterface< D1<T> >;
T x; // identical between D1 and D2
public:
D1(const T &a) { x = a + name.size(); } // refers to base class member
int add(int i, int j) { return i+j; } // different signature between D1 and D2
void more() {} // not present in D1
};
//////////// 2nd PAIR ////////////
class B2 : public BInterface {
public:
B2() : BInterface("B2") { }
};
template<typename T>
class D2 : public B2, public DInterface< D2<T> > {
friend class DInterface< D2<T> >;
T x; // identical between D1 and D2
public:
D2(const T &a) { x = a + name.size(); }
int add(int i, int j, int k) { return i+j+k; } // different signature between D1 and D2
};
// this is just to test that the program compiles and works
int main() {
D1<int> d1(5);
D2<long> d2(6l);
cout << d1.getX();
cout << d1.nameLength();
return 0;
}
여러 사람이 내 실제 문제의 상황은 내가 실제 문제를 설명 아래, 손실됩니다 너무 광범위하고 논평 한 가입일 :
Mathematica이 a C extension API 있습니다. 조밀하거나 희소 한 배열 또는 이미지와 같은 특정 데이터 유형은 C에서 조작 될 수 있습니다. C++ 인터페이스를 훨씬 쉽게 사용할 수 있도록 작업 중입니다. 이 시스템은 인터페이스 생성기에도 포함되어 있습니다. 많은 접착제 코드가 Mathematica의 C++ 클래스 인터페이스의 상징적 표현을 기반으로 자동 생성됩니다. Here's an older version of the system.
이제 이미지 처리 작업을하고 있습니다. Mathematica는 Image
과 Image3D
을 가지고 있으며 2D와 3D 이미지에 대한 표현이 뚜렷합니다. Image
은 바이트, 16 비트, 부동 소수점 등과 같은 다른 픽셀 유형을 가질 수도 있습니다.
C API는 2D 및 3D 이미지를 포함하여 이들 모두에 대해 단일 표현을 사용하며 MImage
(포인터 유형, 복수 MImages
는 메모리의 동일한 이미지를 가리킬 수 있습니다.
C++에서 2D 및 3D 이미지에 대해 별도의 클래스를 사용하고 픽셀 유형에 템플릿을 템플릿으로 만드는 것이 편리합니다. 위의 D1
및 D2
클래스에 해당합니다. 그러나 일부 경우 픽셀 유형 (픽셀은이 경우 액세스 할 수 없지만 이미지로 다른 작업도 수행 할 수 있음)을 가질 수있는 "일반"이미지로 작동하는 것이 유용합니다.이것이 기본 클래스 B1
과 B2
입니다.
Here's the implementation of 2D image references (아직 완료되지 않았으며 변경 될 예정입니다.) 3D 이미지를 추가해야하는데 많은 코드가 공유됩니다.
너무 광범위하다고 생각합니다. CRTP에 특별히 문제가 있으면 좋은 질문 일 수 있습니다. –
또 다른 것은 DBase가 기본 클래스 (B1 또는 B2)에서 템플리트 화되는 템플리트 DBase의 관점에서 D1 및 D2를 작성하는 것입니다. (따라서 트리는'D1' ->'DBase'->'B1' ->'BInterface'처럼 보일 것입니다.). 또한 자유 함수 (템플릿 화 가능) 또는 전 처리기 매크로; 그것은 모두 당신의 실제 * 문제에 달려 있습니다. –
@MartinBonner 왜 너무 광범위합니까? 문제는 개념에 관한 것이 아닙니다. 그것은 * 하나의 특별한 * 프로그램에 관한 것입니다. 나는 그것을 가능한 한 작게 증류했다. 문제는이 두 쌍의 클래스간에 코드를 공유하는 방법입니다. 이 접근법이이 특별한 경우에 충분히 합리적이라면, 그것은 내가 받아 들일 수있는 대답입니다. 나는 그것이 진실인지 아닌지 판단 할 수 없으며, 나에게 너무 복잡해 보입니다. – Szabolcs