想象一下这种情况:
m1()
,由 C1 m2()
,由 C2 m3()
,由 C3 我想定义带有参数arg
的函数。
void f1(I1 arg) {
use m1()
}
void f2([I1, I2] arg) {
use m1() and m2()
}
void f3([I2, I3] arg) {
use m2() and m3()
}
然后我想定义:
然后我想实例化 C123 并将其与f1
,f2
,f3
一起使用。
C123 obj;
f1(obj);
f2(obj);
f3(obj);
f2
将使用 [C1,C2] 而不是 [I1,I2] 。#include <string>
#include <iostream>
using namespace std;
class C1 {
protected:
int i;
public:
int getI() const { return i; }
void setI(int i_) { i = i_; }
};
class C2 {
protected:
string s;
public:
string getS() const { return s; }
void setS(string s_) { s = s_; }
};
class C3 {
protected:
float f;
public:
float getF() const { return f; }
void setF(float f_) { f = f_; }
};
class C23 : public C2, public C3 {};
class C123 : public C1, public C2, public C3 {};
void f3(C23 arg) {
arg.setS(to_string(arg.getF()));
}
int main() {
C123 obj;
f3(obj);
std::cout << obj.getS();
}
a.cc: In function ‘int main()’:
a.cc:42:9: error: could not convert ‘obj’ from ‘C123’ to ‘C23’
f3(obj);
答案 0 :(得分:0)
是的,这可以通过纯抽象类和多重继承来实现。由于I1
,I2
和I3
之间没有冲突,因此多重继承不会导致任何问题。
示范性实施:
#include <iostream>
class I1 {
public:
virtual void m1() = 0;
virtual ~I1(){};
};
class C1 : public I1 {
public:
void m1() override {
std::cout << "m1() of a C1" << std::endl;
}
~C1(){};
};
class I2 {
public:
virtual void m2() = 0;
virtual ~I2(){};
};
class C2 : public I2 {
public:
void m2() override {
std::cout << "m2() of a C2" << std::endl;
}
~C2(){};
};
class I3 {
public:
virtual void m3() = 0;
virtual ~I3(){};
};
class C3 : public I3 {
public:
void m3() override {
std::cout << "m3() of a C3" << std::endl;
}
~C3(){};
};
class I12 : public I1, public I2 {
public:
virtual ~I12(){};
};
class I23 : public I2, public I3 {
public:
virtual ~I23(){};
};
class I123 : public I12, public I23 {
public:
virtual ~I123(){};
};
class C123 : public I123 {
public:
void m1() override {
std::cout << "m1() of a C123" << std::endl;
}
void m2() override {
std::cout << "m2() of a C123" << std::endl;
}
void m3() override {
std::cout << "m3() of a C123" << std::endl;
}
~C123(){};
};
void f1(I1 &arg) {
std::cout << "f1():" << std::endl;
arg.m1();
}
void f2(I12 &arg) {
std::cout << "f2():" << std::endl;
arg.m1();
arg.m2();
}
void f3(I23 &arg) {
std::cout << "f3():" << std::endl;
arg.m2();
arg.m3();
}
int main() {
C123 object;
f1(object);
f2(object);
f3(object);
return 0;
}
产生以下输出:
f1():
m1() of a C123
f2():
m1() of a C123
m2() of a C123
f3():
m2() of a C123
m3() of a C123
这表明C ++提供了满足您要求的多重继承。但是,我建议您阅读Effective C++ Item 40:明智地使用多重继承。本章建议仅在必要时使用虚拟基类。所以,当你确实拥有一个致命的MI钻石&#34;如果出现冲突,请将所有上述纯虚拟类用作虚拟基类(即通过: virtual public ....
直接从中继承的所有类。成本较低,初始化规则较复杂。
更新
如果要在C123中继承C1,C2和C3的实现(请注意实现继承通常是错误的设计),请执行以下操作:
I1
,I2
,I3
,I12
,I23
,I123
作为虚拟基类,class C123 : virtual public I123, public C1, public C2, public C3
而不重新实现m1()
,m2()
和m3()
。结果输出
f1():
m1() of a C1
f2():
m1() of a C1
m2() of a C2
f3():
m2() of a C2
m3() of a C3
答案 1 :(得分:0)
C ++输入与Java的输入不同,因此通过重新评估您的需求来解决问题通常更容易。使用旧行为导出新对象有两种不同的方法,了解每种对象的好处非常重要。
继承是第一个,您基本上复制旧对象的功能,然后向其添加更多内容。当您有许多不同的父对象都实现相同的功能时,这就成了一个问题。第二个是组合,您可以在新对象中放置许多对象。然后,新对象可以“选择”使用哪些行为,通常会消除多重继承的歧义。它必须以您必须定义行为为代价,因为编译器无法对您的预期行为做出如此深刻的推理。
在您的情况下,我读到您有3个不同的对象,其行为不同,您需要撰写(而不是继承)他们的行为。您描述需要为组合对象中包含的任何m()
调用I#
;这很容易。
定义包装器对象,并有条件地调用每个接口提供的m
函数:
class Wrapper {
I1 slot1;
I2 slot2;
I3 slot3;
Wrapper(i1 = I1.default(), i2 = I2.default(), i3 = I3.default()) {
slot1 = i1;
slot2 = i2;
slot3 = i3;
}
void foo() {
// The default instances don't do anything on m()
slot1::m();
slot2::m();
slot3::m();
}
}
毫无疑问,有很多改进和优化的空间,但这是一般的想法。
查看示例代码,您可能希望查看Logger
的概念以进行调试。许多语言都使用它们,并且您“订阅”cout/cerr
到程序的不同部分提供的不同记录器供稿。例如,您可能有一个物理记录器,另一个用于图形。
它们与您选择性输出对象中可用的不同数据类型非常相似。
答案 2 :(得分:0)
- 这在C ++中是否可行?
醇>
是的,可以用C ++做到这一点。
#include <string>
#include <iostream>
using namespace std;
class I1 {
public:
virtual int getI() const = 0;
virtual void setI(int i) = 0;
};
class I2 {
public:
virtual string getS() const = 0;
virtual void setS(string s) = 0;
};
class I3 {
public:
virtual float getF() const = 0;
virtual void setF(float f) = 0;
};
class C1 : public I1 {
protected:
int i;
public:
int getI() const { return i; }
void setI(int i_) { i = i_; }
};
class C12 : public I1, public I2 {
protected:
int i;
string s;
public:
int getI() const { return i; }
void setI(int i_) { i = i_; }
string getS() const { return s; }
void setS(string s_) { s = s_; }
};
class C123 : public I1, public I2, public I3 {
protected:
int i;
string s;
float f;
public:
int getI() const { return i; }
void setI(int i_) { i = i_; }
string getS() const { return s; }
void setS(string s_) { s = s_; }
float getF() const { return f; }
void setF(float f_) { f = f_; }
};
template<class T>
void f1(const T& c1)
{
cout << "f1:\n";
cout << " getI: " << c1.getI() << endl;
}
template<class T>
void f2(const T& c12)
{
cout << "f2:\n";
cout << " getI: " << c12.getI() << endl;
cout << " getS: " << c12.getS() << endl;
}
template<class T>
void f3(const T& c23)
{
cout << "f3:\n";
cout << " getS: " << c23.getS() << endl;
cout << " getF: " << c23.getF() << endl;
}
void test()
{
C1 c1;
c1.setI(1);
f1(c1);
cout << "\n===== " << endl;
C12 c12;
c12.setI(12);
c12.setS("str12");
f1(c12);
f2(c12);
cout << "\n===== " << endl;
C123 c123;
c123.setI(123);
c123.setF(1.23f);
c123.setS("str123");
f1(c123);
f2(c123);
f3(c123);
cout << "\n===== " << endl;
}
int main()
{
test();
}
- 没有接口可以吗?例如。函数f2取[C1,C2]而不是[I1,I2]。
醇>
是的,没有接口就可以做到这一点。
#include <string>
#include <iostream>
using namespace std;
class C1 {
protected:
int i;
public:
int getI() const { return i; }
void setI(int i_) { i = i_; }
};
class C2 {
protected:
string s;
public:
string getS() const { return s; }
void setS(string s_) { s = s_; }
};
class C3 {
protected:
float f;
public:
float getF() const { return f; }
void setF(float f_) { f = f_; }
};
class C12 : public virtual C1, public virtual C2
{
};
class C23 : public virtual C2, public virtual C3
{
};
class C123 : public virtual C1, public virtual C12, public virtual C23
{
};
void f1(const C1& c1)
{
cout << "f1:\n";
cout << " getI: " << c1.getI() << endl;
}
void f2(const C12& c12)
{
cout << "f2:\n";
cout << " getI: " << c12.getI() << endl;
cout << " getS: " << c12.getS() << endl;
}
void f3(const C23& c23)
{
cout << "f3:\n";
cout << " getS: " << c23.getS() << endl;
cout << " getF: " << c23.getF() << endl;
}
void test()
{
C1 c1;
c1.setI(1);
f1(c1);
cout << "\n===== " << endl;
C12 c12;
c12.setI(12);
c12.setS("str12");
f1(c12);
f2(c12);
cout << "\n===== " << endl;
C123 c123;
c123.setI(123);
c123.setF(1.23f);
c123.setS("str123");
f1(c123);
f2(c123);
f3(c123);
cout << "\n===== " << endl;
}
int main()
{
test();
}
一些解释。如果你需要你的f2只采用C1和C2(没有C3)那么它必须是在C1和C2上都继承的单独类型。 f3也是如此。然后,如果您遵循该逻辑并创建类C12
和C23
而不使用虚拟继承,那么现在应该从C12和C23继承的C123将以C2的多个副本结束,并且当您调用f2时和f3你会从getS
获得不同的值。虚拟继承确保继承层次结构中只有一个类的副本。
a&#34; union&#34; C123类,它继承了现有类C1,C2,C3的实现方法
#include <string>
#include <iostream>
using namespace std;
class I1 {
public:
virtual int getI() const = 0;
virtual void setI(int i) = 0;
};
class I2 {
public:
virtual string getS() const = 0;
virtual void setS(string s) = 0;
};
class I3 {
public:
virtual float getF() const = 0;
virtual void setF(float f) = 0;
};
class I12 : virtual public I1, virtual public I2 {};
class I23 : virtual public I2, virtual public I3 {};
class I123 : virtual public I12, virtual public I23 {};
class C1 : virtual public I1 {
protected:
int i;
public:
int getI() const { return i; }
void setI(int i_) { i = i_; }
};
class C2 : virtual public I2 {
protected:
string s;
public:
string getS() const { return s; }
void setS(string s_) { s = s_; }
};
class C3 : virtual public I3 {
protected:
float f;
public:
float getF() const { return f; }
void setF(float f_) { f = f_; }
};
class C12 : public I12, public C1, public C2 {};
class C123 : public I123, public C1, public C2, public C3 {};
void f1(const I1& c1)
{
cout << "f1:\n";
cout << " getI: " << c1.getI() << endl;
}
void f2(const I12& c12)
{
cout << "f2:\n";
cout << " getI: " << c12.getI() << endl;
cout << " getS: " << c12.getS() << endl;
}
void f3(const I123& c23)
{
cout << "f3:\n";
cout << " getS: " << c23.getS() << endl;
cout << " getF: " << c23.getF() << endl;
}
void test()
{
C1 c1;
c1.setI(1);
f1(c1);
cout << "\n===== " << endl;
C12 c12;
c12.setI(12);
c12.setS("str12");
f1(c12);
f2(c12);
cout << "\n===== " << endl;
C123 c123;
c123.setI(123);
c123.setF(1.23f);
c123.setS("str123");
f1(c123);
f2(c123);
f3(c123);
cout << "\n===== " << endl;
}
int main()
{
test();
}
所有解决方案都应产生此输出:
f1:
getI: 1
=====
f1:
getI: 12
f2:
getI: 12
getS: str12
=====
f1:
getI: 123
f2:
getI: 123
getS: str123
f3:
getS: str123
getF: 1.23
=====