如何实现接口继承(老问题,但找不到答案)

tutu_cloud 2008-02-19 06:46:22
有两个抽象类,父类Parent,子类Child,如:

class Parent
{
public:
virtual ~Parent();
virtual void FuncForParent() = 0;
};

class Child : public Parent
{
public:
virtual void FuncForChild() = 0;
};

根据这两个抽象类写出实现类ParentImpl和ChildImpl,但不知道怎么写了……
想了几种方法,好像都不怎么样。

class ParentImpl : public Parent
{
public:
void FuncForParent() {};
};
class ChildImpl : public Child, public ParentImpl
{
public:
void FuncForChild() {}
};
// 这样写好像没法实例化ChildImpl


class Child : virtual public Parent
{
...
};
class ParentImpl : virtual public Parent
{
public:
void FuncForParent() {};
};
class ChildImpl : public Child, public ParentImpl
{
public:
void FuncForChild() {}
};
// 这样写的话可以使用,但是需要改原先的接口


template<class _I=Parent>
class ParentImpl : public _I
{
public:
void FuncForParent() {};
};
template<class _I=Child>
class ChildImpl : public ParentImpl<_I>
{
public:
void FuncForChild() {}
};
typedef ParentImpl<> ParentImplType;
typedef ChildImpl<> ChildImplType;
// 这样写的话也可以使用,但ChildImplType*无法转换成ParentImplType*


我的问题是,C++里面如何才能实现接口继承,且满足
1. ChildImpl能够尽可能简单的重用ParentImpl中的实现(即ChildImpl不需要再次实现FuncForParent)
2. 实现类之间有继承关系(第三个例子就不是)
3. 最好不要改变原有接口声明(如第二个例子)

多谢

注:以上的代码都是直接写的,只是表示一下想法而已,可能有语法错误,见谅。
...全文
271 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
txlj_ok 2008-02-25
  • 打赏
  • 举报
回复
C++工程师


任职条件
1.C++水平熟练以上。
2.Windows开发平台
3.一年以上工作经验。

联系方式:yang_jinxiu@live.cn
电话:82845151
e-mail:yjx@ok.com.cn
工作地点:北京
tutu_cloud 2008-02-25
  • 打赏
  • 举报
回复
生病了,卧床在家……

看来的确没什么非常好的方法,就此结贴。

多谢各位
taodm 2008-02-20
  • 打赏
  • 举报
回复
看《重构》
tutu_cloud 2008-02-20
  • 打赏
  • 举报
回复
to arong1234 & LS_Winson:
似乎二位的方法都需要在子接口的实现类中实现所有的虚函数(包括父接口),那么在接口继承层次较多,且父接口的虚函数远多于子接口的虚函数的情况下,这种方法似乎会非常烦琐。假设有窗口系统接口的继承关系(当然实际的窗口系统并不一定使用纯抽象类,这里只是举例而已):Control<--TextField<--PasswordField,其中Control和TextField可能声明了很多虚函数,而PasswordField只声明了两个新的虚函数get_replaced_char和set_replaced_char。如果按照两位的实现方法,则PasswordField的实现类必须声明Control和TextField中所有的虚函数(即使每个实现函数只是调用父类的某个函数)。结果就是PasswordField的实现类的声明非常庞大,而真正有意义的函数只有两个。随着继承关系越来越复杂,越来越多的开发时间将花费在子实现类再次声明父接口的虚函数,并调用父实现类的函数上。如果在开发的过程中,父接口因为某些原因必须做一些更改,如改变一个函数名(虽说接口定义后应该保持不变,但我想应该有不少人碰上过类似的情况),则所有实现类都必须做相应更改。

to taodm:
我知道接口继承并不是为了重用代码,但对于接口的实现者来说,接口继承暗示了接口所代表的对象或概念之间有着逻辑上的继承关系,那么当我们实现好父接口后,在实现子接口的过程中,自然而然地会想到重用父接口的实现代码。换句话说,在这里我并不关心为什么程序会设计成接口继承这种形式,而只是试图找出一种实现接口继承的比较好的方法。
taodm 2008-02-20
  • 打赏
  • 举报
回复
楼主注意,接口继承不是为了重用代码。
不要把2者绞在一起。
Jim_King_2000 2008-02-20
  • 打赏
  • 举报
回复
如果有ISampleSon,也是可以搞定的。LZ可以看看《设计模式》之bridge模式。内容太多,不方便写出来。
至于第二个问题,那是没办法的。如果不使用bridge模式,情况会更糟。因此,还是忍受一下吧,毕竟没有完美的东西。
tutu_cloud 2008-02-20
  • 打赏
  • 举报
回复
to Jim_King_2000:
这个……怎么说呢,
1. 假设存在ISample<--ISampleSon,怎么定义SampleSon,SampleSonImp和SampleSonImplXXX呢?这才是问题的关键。
2. 假设ISample有二十个虚函数,Sample就得定义20个转发函数,SampleImpl就得声明20个虚函数,再加上SampleImplXXX中真正的20个实现函数。再假设ISampleSon同样有几十个函数……再假设ISampleGrandson…………会死人的……
Jim_King_2000 2008-02-20
  • 打赏
  • 举报
回复
嗯。这样的要求可以用bridge模式来实现。
我们假设接口名称为ISample,接口实现类名称为Sample,那么Sample类可以桥接另外一个真正实现了代码的类SampleImpl。具体代码如下:

// ISample.h
struct ISample
{
virtual void foo(void) = 0;
};



// Sample.h
#include "ISample.h"

class SampleImpl;
class Sample : public ISample
{
public:
Sample(void);
virtual void foo(void);

private:
SampleImpl *imp_;
};

// Sample.cpp
#include "Sample.h"
#include "SampleImpl.h"

Sample::Sample(void)
: imp_(CreateSampleImpl())
{
}

void Sample::foo(void)
{
imp_->foo();
}

我们可以看到,Sample类虽然号称接口实现类,但其实只是一个空壳,它只是负责把调用转发给SampleImpl类。
下面SampleImpl类隆重出场。

// SampleImpl.h
class SampleImpl
{
public:
virtual void foo(void) = 0;
};

SampleImpl仍然只是个摆设。真正干活的类在这里:

// SampleImplOne.h
#include "SampleImpl.h"

class SampleImplOne : SampleImpl
{
public:
SampleImplOne(void);
virtual void foo(void);
};

// SampleImplOne.cpp
#include "SampleImplOne.h"

SampleImplOne::SampleImplOne(void)
{
...
}

void SampleImplOne::foo(void)
{
// foo函数的第一种实现
...
}



// SampleImplTwo.h
#include "SampleImpl.h"

class SampleImplTwo : SampleImpl
{
public:
SampleImplTwo(void);
virtual void foo(void);
};

// SampleImplTwo.cpp
#include "SampleImplTwo.h"

SampleImplTwo::SampleImplTwo(void)
{
...
}

void SampleImplTwo::foo(void)
{
// foo函数的第二种实现
...
}

CreateSampleImpl函数就是依据某种规则创建出SampleImplOne或者SampleImplTwo对象(当然还有可能更多),然后把它的地址给imp_做初始化。如果LZ希望重用一些东西,那么可以在SampleImpl类里面实现它们,这样具体类SampleImplOne或者SampleImplTwo就可以把这样的代码直接拿过来用了。
tutu_cloud 2008-02-20
  • 打赏
  • 举报
回复
to Jim_King_2000:
我可能写得不是很清楚。我所举的例子只是些我在提这个问题时所想到的一些实现方式,并不代表我倾向于任何一种模式或实现方式。我同样也不关心接口继承和重用代码之间是否有必然联系,以及用户怎样使用接口。我所关心的是,如果已经存在一系列有继承关系的接口或概念(在此处的每一个接口/概念都可以代表一个独立的对象,如Control<--TextField<--PasswordField,而不是一个抽象概念和若干个具体对象,如Control<--TextField与Control<--PasswordField),需要找出一种比较好的实现方法。当接口数量很多时,我认为评价一个实现是否比较好的标准之一就是重用代码,毕竟写多错多。

to czp_opensource:
这条声明的目的是,首先ChildImpl必须实现Child,其次,ChildImpl最好也是ParentImpl的子类。第二个目的并非必要,只是可以在实现的逻辑处理时带来一些便利而已。


在这个问题中,我的角色并不是程序的设计者,而只是接口的实现者。我的任务前提是一堆有继承关系的接口/概念,我的任务就是实现这些接口/概念。这些接口的层次可能很多,每个接口的方法可能很多。所以我的目的就是找一种方式能够方便接口的实现者,也就是我自己。
czp_opensource 2008-02-20
  • 打赏
  • 举报
回复
LZ你的想法就不对。 
请解释一下这句: class ChildImpl : public Child, public ParentImpl   你要做什么, 目的是什么?
Jim_King_2000 2008-02-20
  • 打赏
  • 举报
回复
看到这里我仍然不是很理解LZ的问题。我猜可能Bridge模式是LZ所需要的。建议LZ阅读《设计模式》。不过有一点是肯定的,接口继承不存在重用代码的问题,它纯粹只是一个接口协议。
LS_Winson 2008-02-19
  • 打赏
  • 举报
回复

class ParentImpl : public Parent
{
public:
void FuncForParent() {};
};
class ChildImpl : public Child, public ParentImpl
{
public:
void FuncForChild() {};
void FuncForParent() {ParentImpl::FuncForParent();};
};


我说的一定要写出接口函数就是这个意思
arong1234 2008-02-19
  • 打赏
  • 举报
回复
其实基类的CParentImpl根本不应该实现啊,所以的都在ChildImpl实现即可
如果你一定要用一个基类,只要把你想重用的代码放在一个函数内,然后基类派生类分别调用

纯虚函数比较特殊,因此你每个都需要实现,不能借希望从上层继承

而且:由于接口发生变化后,很多依赖于接口的程序都要修改,因此现在接口都不说继承,而说实现。COM本质论好象这么说过

// test2.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

class Parent
{
public:
virtual ~Parent(){};
virtual void FuncForParent() = 0;
};

class Child : public Parent
{
public:
virtual void FuncForChild() = 0;
};
class ParentImpl : public Parent
{
public:
void ShareFunc(){};
void FuncForParent() {ShareFunc();};
};
class ChildImpl : public Child, public ParentImpl
{
public:
void FuncForChild() {};
void FuncForParent() {ShareFunc();};
};

int _tmain(int argc, _TCHAR* argv[])
{
Child*pChild=new ChildImpl();
return 0;
}


tutu_cloud 2008-02-19
  • 打赏
  • 举报
回复
to jim_king_2000:
可能我举的例子有些误导。我这里并不是强调模式,而是说在存在一系列有继承关系的接口时,如何提供实现这些接口的代码。在这个例子里,用户能看到的只有Parent和Child这两个抽象的类,我的目标就是提供这两个抽象类的实现,且最大限度的重用代码。

to LS_Winson:
那么怎么改接口呢?能提供最简单的接口和实现的实例吗?

谢谢
LS_Winson 2008-02-19
  • 打赏
  • 举报
回复
还是要把接口代码再写一次的吧...在其中选择某个基类函数来调用

怎么感觉这个设计是种菱形继承关系呢...
Jim_King_2000 2008-02-19
  • 打赏
  • 举报
回复
接口继承跟impl模式似乎没什么关系吧?LZ到底想问什么问题?

65,210

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧