y**b 发帖数: 10166 | 1 父类B,
子类D1,D2,D3,
子类有很多相同的操作,也有几个不同的操作,比如D1op, D2op, D3op.
现在有一个C类中包含了B类指针,来操作其三个子类的对象(混合出现),
也就是有这种情况:
B *pB,
pB->D1op
pB->D2op
pB->D3op
显然,编译通不过,因为B类并没有定义这些操作。
想了几个办法:
1. 在B类中用虚函数定义这些操作,三个子类分别覆盖,如果没有动作就为空。
但这带来一个问题:B类中接口太宽,本来三个子类各自不同的操作,结果
父类反而都得有;如果再添加个子类及不同操作,那B类又得添加接口。感觉
特别不合理,这叫什么问题?
2.使用RTTI和向下转换dynamic_cast,B类转换成不同子类,可是这个转换要
做很多检测,还不一定转换成功;倒是static_cast反而明确一些,也最简单
可行?
3.碰巧C类使用B类三个不同子类(每次只用一个子类)作为组成部分,可以使用
类模板,也就是说用B类三个不同子类作为模板形参来构造C类。这样C类其实
也形成了三个子类,分别对应B类的三个子类,但是失去了使用B类的便利。
还是这几种办法根本就不对?请指教,多谢。 |
A*******e 发帖数: 2419 | 2 操作接口都不一样,何必要从同一个基类继承?
【在 y**b 的大作中提到】 : 父类B, : 子类D1,D2,D3, : 子类有很多相同的操作,也有几个不同的操作,比如D1op, D2op, D3op. : 现在有一个C类中包含了B类指针,来操作其三个子类的对象(混合出现), : 也就是有这种情况: : B *pB, : pB->D1op : pB->D2op : pB->D3op : 显然,编译通不过,因为B类并没有定义这些操作。
|
y**b 发帖数: 10166 | 3 嗯,我没说清楚,大部分操作接口都是相同的,就有几个不同。我只列了几个不同的,
改了。 |
p***o 发帖数: 1252 | 4 把不同的改成相同的。
【在 y**b 的大作中提到】 : 嗯,我没说清楚,大部分操作接口都是相同的,就有几个不同。我只列了几个不同的, : 改了。
|
A*******e 发帖数: 2419 | 5 子类自有的方法根本不应该通过父类调用
【在 y**b 的大作中提到】 : 嗯,我没说清楚,大部分操作接口都是相同的,就有几个不同。我只列了几个不同的, : 改了。
|
y**b 发帖数: 10166 | 6 也许是这个道理。
可是生成这些子类对象的时候,就是用的父类指针,这还是比较普遍的吧?那怎么调用
自有方法呢。
【在 A*******e 的大作中提到】 : 子类自有的方法根本不应该通过父类调用
|
A*******e 发帖数: 2419 | 7 建模有问题。可以想想该如何重新设计。
【在 y**b 的大作中提到】 : 也许是这个道理。 : 可是生成这些子类对象的时候,就是用的父类指针,这还是比较普遍的吧?那怎么调用 : 自有方法呢。
|
y**b 发帖数: 10166 | 8 想过这么做,可是发现:
1. 有两个个成员函数signature略有不同(形参个数),但这也不是问题,仍然可以把它
们写成一样的signature,只是某些参数对某些子类是不需要的。
2. 有几个成员函数名字(含有物理意义)不同,若改成相同,倒是可以实现,但子类的
个性有点混淆啊,而且父类接口偏宽?
感觉这个思路和向下static_cast比,那个更好呢?也不局限于我这个例子,就普遍性
而言呢?
多谢大家指点。
【在 p***o 的大作中提到】 : 把不同的改成相同的。
|
p***o 发帖数: 1252 | 9 你这属于没抽象好。
如果子类参数不同就不应该由父类*直接*管理,参数可以交给子类管理最好,
不行的话可以考虑把参数装到一个map里由父类传给子类。
父类能在同一个函数里调不同子类的不同函数那说明他们是有联系的,有联系
就可以抽象出共性来。
【在 y**b 的大作中提到】 : 想过这么做,可是发现: : 1. 有两个个成员函数signature略有不同(形参个数),但这也不是问题,仍然可以把它 : 们写成一样的signature,只是某些参数对某些子类是不需要的。 : 2. 有几个成员函数名字(含有物理意义)不同,若改成相同,倒是可以实现,但子类的 : 个性有点混淆啊,而且父类接口偏宽? : 感觉这个思路和向下static_cast比,那个更好呢?也不局限于我这个例子,就普遍性 : 而言呢? : 多谢大家指点。
|
y**b 发帖数: 10166 | 10 我是这样想的:能抽象出共性的尽可能抽出来放在父类,但是具体的差别还是放在子类
,这个设计应该算正常的。
但是用到子类那些有具体差别(其实概念上还算很接近)的接口时,不应该通过父类指针
来操作。
比如有30个接口抽象到父类了,还有三五个属于子类不同的属性。那30个接口采用父类
指针(比如含有大量父类指针的一个链表)进行操作非常方便,就那三五个子类特有的接
口得通过子类指针来操作。
我的问题好像在于:生成子类对象的时候直接采用了父类指针,结果遇到子类特有属性
的时候就得向下转换。如果生成子类对象的时候全部采用子类指针,遇到共性的时候将
这些子类指针(或者其容器)传给父类指针,好像问题就解决了;代价就是在C类中多维
护几个子类指针的容器并把它们适当地传给父类指针的容器,但是不会遇到向下转换的
问题。好像这样才是合理的做法?
之所以出这个问题,是因为原来程序只有B类,后来将B类改成D1类,同时添加D2类,再
重写B类,也为以后添加D3,D4做些准备。C类里面就一直想着偷懒用原来代码不变,其
实稍微改改就更合理了。 |
|
|
y**b 发帖数: 10166 | 11 麻烦也再看看我后面补充的想法。
【在 A*******e 的大作中提到】 : 建模有问题。可以想想该如何重新设计。
|
O*******d 发帖数: 20343 | |
m*********n 发帖数: 28 | 13 后面的补充想法是对的。给你个范例程序
struct SexOrgan {
};
struct Asshole : public SexOrgan {
};
struct Dick : public SexOrgan {
};
struct Pussy : public SexOrgan {
void Eat(Dick& dick) {
};
};
void B2B(Pussy& p0, Pussy& p1) {
}
struct HumanBeing {
virtual void BangWith(HumanBeing & that) {
// take off all clothes;
}
};
struct Female;
struct Male : public HumanBeing {
virtual void BangWith(HumanBeing& that) {
HumanBeing::BangWith(that);
Female* female = dynamic_cast (&that);
if (female) {
Fuck(female->ShowB());
} else {
throw std::runtime_error("female only.");
}
}
SexOrgan& ShowStuff() {
return dick;
}
void Fuck(Pussy& pussy) {
}
Dick dick;
};
struct Gay : public HumanBeing {
virtual void BangWith(HumanBeing& that) {
HumanBeing::BangWith(that);
Gay* gay = dynamic_cast (&that);
if (gay) {
FuckAssole(gay->Bonus());
gay->FuckAssole(Bonus());
} else {
throw std::runtime_error("No gay no sex.");
}
}
Asshole& Bonus() {
return asshole;
}
void FuckAssole(Asshole& asshole) {
}
Asshole asshole;
};
struct Female : public HumanBeing {
virtual void BangWith(HumanBeing& that) {
HumanBeing::BangWith(that);
Male* male = dynamic_cast (&that);
if (male) {
pussy->Eat(male->ShowStuff());
} else {
Female* female = dynamic_cast (&that);
if (Female) {
B2B(pussy, female->ShowB());
} else {
throw std::runtime_error("Fuck off u gay!");
}
}
}
virtual Pussy& ShowB() {
return pussy;
}
Pussy pussy;
};
struct SexLifeWithoutProblem {
void Enjoy() {
for (Male* m : males) {
for (Female* f : females) {
m->BangWith(*f);
}
}
}
void Disgusting() {
for (Gay* g : gays) {
for (Gay* g1 : gays) {
if (g != g1) {
g->BangWith(*g1);
} else {
// unless this gay has a really long one...
g->BangWith(*g);
}
}
}
}
std::vector males;
std::vector females;
std::vector gays;
};
struct SexLifeWithProblem {
void TryIt() {
for (HumanBeing* p : people) {
for (HumanBeing* p1 : people) {
// hmmmm.... have to deal with these annoying gays...
p->BangWith(*p1);
}
}
}
std::vector people;
};
【在 y**b 的大作中提到】 : 麻烦也再看看我后面补充的想法。
|
m*********n 发帖数: 28 | 14 SexLifeWithoutProblem 里面不同的子类放在不同的地方。做爱时候不会出现任何问题。
SexLifeWithProblem 里面不同的子类放在同一个地方做爱的时候就会有问题
:D
【在 y**b 的大作中提到】 : 麻烦也再看看我后面补充的想法。
|
c*********e 发帖数: 16335 | 15 HumanBeing 有3个子类:Male, Female, Gay。
你这个是用if...else把不同的子类分开,如果子类是Male,这么做;如果子类是Female,
这么做. 那么,如果再要加一个新的子类,Transgender,你的很多函数要重新写了,比
如下面这个BangWith()函数。况且,gay,可以是Male, or Female.
struct Female : public HumanBeing {
virtual void BangWith(HumanBeing& that) {
HumanBeing::BangWith(that);
Male* male = dynamic_cast (&that);
if (male) {
pussy->Eat(male->ShowStuff());
} else {
Female* female = dynamic_cast (&that);
if (Female) {
B2B(pussy, female->ShowB());
} else {
throw std::runtime_error("Fuck off u gay!");
}
}
}
。。。
【在 m*********n 的大作中提到】 : 后面的补充想法是对的。给你个范例程序 : struct SexOrgan { : }; : struct Asshole : public SexOrgan { : }; : struct Dick : public SexOrgan { : }; : struct Pussy : public SexOrgan { : void Eat(Dick& dick) { : };
|
m*********n 发帖数: 28 | 16 这个就是运行时的不同处理了必须用dynamic_cast做。
Female,
【在 c*********e 的大作中提到】 : HumanBeing 有3个子类:Male, Female, Gay。 : 你这个是用if...else把不同的子类分开,如果子类是Male,这么做;如果子类是Female, : 这么做. 那么,如果再要加一个新的子类,Transgender,你的很多函数要重新写了,比 : 如下面这个BangWith()函数。况且,gay,可以是Male, or Female. : struct Female : public HumanBeing { : virtual void BangWith(HumanBeing& that) { : HumanBeing::BangWith(that); : Male* male = dynamic_cast (&that); : if (male) { : pussy->Eat(male->ShowStuff());
|
s******y 发帖数: 416 | 17 如果函数的sig相同,建议使用函数指针。在父类里设置一个接口就好。
【在 y**b 的大作中提到】 : 父类B, : 子类D1,D2,D3, : 子类有很多相同的操作,也有几个不同的操作,比如D1op, D2op, D3op. : 现在有一个C类中包含了B类指针,来操作其三个子类的对象(混合出现), : 也就是有这种情况: : B *pB, : pB->D1op : pB->D2op : pB->D3op : 显然,编译通不过,因为B类并没有定义这些操作。
|
c*********e 发帖数: 16335 | 18 能写个代码做例子吗?
【在 s******y 的大作中提到】 : 如果函数的sig相同,建议使用函数指针。在父类里设置一个接口就好。
|
b*******s 发帖数: 5216 | |
L****8 发帖数: 3938 | 20 不要搞这么多继承
【在 y**b 的大作中提到】 : 父类B, : 子类D1,D2,D3, : 子类有很多相同的操作,也有几个不同的操作,比如D1op, D2op, D3op. : 现在有一个C类中包含了B类指针,来操作其三个子类的对象(混合出现), : 也就是有这种情况: : B *pB, : pB->D1op : pB->D2op : pB->D3op : 显然,编译通不过,因为B类并没有定义这些操作。
|
|
|
p*****2 发帖数: 21240 | |
y**b 发帖数: 10166 | 22 原来是典型的依赖倒置原则,父类不应该依赖于之类。
1. 在B类中用虚函数定义这些操作,三个子类分别覆盖,如果没有动作就为空。
但这带来一个问题:B类中接口太宽,本来三个子类各自不同的操作,结果
父类反而都得有;如果再添加个子类及不同操作,那B类又得添加接口。感觉
特别不合理,这叫什么问题?
【在 y**b 的大作中提到】 : 麻烦也再看看我后面补充的想法。
|
c*********e 发帖数: 16335 | 23 en,感觉精华在这
virtual void BangWith(HumanBeing& that) {
HumanBeing::BangWith(that);
Male* male = dynamic_cast (&that);
if (male) {
...
} else {
...
}
【在 m*********n 的大作中提到】 : 后面的补充想法是对的。给你个范例程序 : struct SexOrgan { : }; : struct Asshole : public SexOrgan { : }; : struct Dick : public SexOrgan { : }; : struct Pussy : public SexOrgan { : void Eat(Dick& dick) { : };
|
g****t 发帖数: 31659 | 24 定义个interface,或者用其他的语法糖。
但你既然问了这个问题,多半会被这些乱七八糟的东西
弄的很烦。
不如直接用 函数指针 完整的文档
另外这跟语言有关
Python meta programming 可能可以直接加函数进去 |
g****t 发帖数: 31659 | 25 Python可以运行时直接往类里面加lambda
这可能是最糙快猛的办法了
: 用lambda很容易就解耦了吧?
【在 p*****2 的大作中提到】 : 用lambda很容易就解耦了吧?
|
L****8 发帖数: 3938 | 26 oop 继承 是个垃圾 多少年了 毒害人
【在 y**b 的大作中提到】 : 父类B, : 子类D1,D2,D3, : 子类有很多相同的操作,也有几个不同的操作,比如D1op, D2op, D3op. : 现在有一个C类中包含了B类指针,来操作其三个子类的对象(混合出现), : 也就是有这种情况: : B *pB, : pB->D1op : pB->D2op : pB->D3op : 显然,编译通不过,因为B类并没有定义这些操作。
|
c*********e 发帖数: 16335 | 27 继承还是有用的,java,c#的编程方法是正确的。
【在 L****8 的大作中提到】 : oop 继承 是个垃圾 多少年了 毒害人
|
z*********n 发帖数: 1451 | 28 没有具体代码,不知道详情,但最简单的办法肯定是朝着统一不同Op的接口这个方向努
力,至少统一返回值?可用的工具包括模板,变长参数列表,或者lambda
如果你能统一函数接口,很有可能可以避免dynamic_cast这种反oop设计原则的语句。
如果可以,最好贴一段短的,精简的样例代码供大家参考。 |