使用其他基类的方法满足纯抽象方法的最简单方法是什么
What's the simplest way to satisfy a pure abstract method with methods from other base classes
编辑:根据一些评论,简单的意思是a(代码更少,b(易于维护,c(很难出错。
编辑#2:此外,如果确实简化了InterfaceImpl
的实现,那么使用包含而不是私有继承也不会令人反感。
目前,我知道的唯一方法是让实现者定义抽象方法,并将调用委托给目标基类型的方法。示例:
#include <iostream>
#include <memory>
class Interface
{
public:
virtual void method1() = 0;
virtual void method2(int x) = 0;
};
class MethodOneImpl
{
private:
void method1(int x)
{ std::cout << "MethodOneImpl::method1() " << x << std::endl; }
public:
void method1() { method1(0); }
};
class MethodTwoImpl
{
public:
void myFunc(int x)
{ std::cout << "MethodTwoImpl::myFunc(x)" << x << std::endl; }
};
class InterfaceImpl : public Interface
, private MethodOneImpl
, private MethodTwoImpl
{
public:
virtual void method1() { MethodOneImpl::method1(); }
virtual void method2(int x) { MethodTwoImpl::myFunc(x); }
};
int main()
{
std::unique_ptr<Interface> inf;
inf.reset(new InterfaceImpl);
inf->method1();
inf->method2(0);
// This should be disallowed!
// std::unique_ptr<MethodOneImpl> moi;
// moi.reset(new InterfaceImpl);
}
起初,我认为这可能会解决问题:
class InterfaceImpl : public Interface
, private MethodOneImpl
, private MethodTwoImpl
{
public:
using MethodOneImpl::method1;
// Obviously this wouldn't work as the method names don't match.
//using MethodTwoImpl::???
};
第一个using语句将使两个MethodOneImpl::method1
方法都是公共的,但它实际上并没有履行与Interface
的约定,并且它修改了MethodOneImpl::method1(int)
的可访问性。很明显,我们不能将这个解决方案与method2
一起使用,因为名称不匹配。
FWIW,我有一个我认为是解决方案,但它根本不是标准的一部分(换句话说,它不会编译(。我正在考虑向C++委员会提出一个建议;如果有人有任何建议,我将感谢下面的任何评论(但请不要将建议作为答案提交(。
另一个选项(至少在使用MS VC++时(是使用虚拟继承:
struct MyInterface
{
virtual void Method1() = 0;
virtual void Method2() = 0;
};
class Method1Impl : public virtual MyInterface
{
virtual void Method1() { _tprintf( _T("Method1n") ); }
};
class Method2Impl : public virtual MyInterface
{
virtual void Method2() { _tprintf( _T("Method2n") ); }
};
class InterfaceImpl : public virtual MyInterface,
private Method1Impl,
private Method2Impl
{
};
void TestWeirdInterfaceImpl()
{
MyInterface* pItf = new InterfaceImpl();
pItf->Method1();
pItf->Method2();
}
虽然这似乎有效并满足了您的需求(C4250中的asside警告,您将不得不使用#pragma进行抑制(,但这不是我的方法。(我相信虚拟继承仍然不是所有编译器都支持的,但我可能错了(。
我可能会使用包含,一旦样板代码是标识符,就把它包装成某种宏映射(类似于ATL或MFC中的映射(,这将使它非常非常难搞砸。
所以这将是我的宏观方法:
struct MyInterface
{
virtual float Method1( int x ) = 0;
virtual int Method2( float a, float b ) = 0;
virtual void Method3( const TCHAR* sz ) = 0;
};
class Method1Impl
{
public:
float Method1( int x ) {
_tprintf( _T("Method1: %dn"), x ); return 5.0;
}
};
class Method2and3Impl
{
public:
int Method2( float a, float b ) {
_tprintf( _T("Method2: %f, %fn"), a, b ); return 666;
}
void Method3( const TCHAR* sz ) {
_tprintf( _T("Method3: %s"), sz );
}
};
#define DECLARE_METHOD0( MethodName, Obj, R )
virtual R MethodName() { return Obj.MethodName(); }
#define DECLARE_METHOD1( MethodName, Obj, R, A1 )
virtual R MethodName( A1 a1 ) { return Obj.MethodName( a1 ); }
#define DECLARE_METHOD2( MethodName, Obj, R, A1, A2 )
virtual R MethodName( A1 a1, A2 a2 ) { return Obj.MethodName( a1, a2 ); }
class InterfaceImpl : public MyInterface
{
public:
DECLARE_METHOD1( Method1, m_method1Impl, float, int );
DECLARE_METHOD2( Method2, m_method2and3Impl, int, float, float );
DECLARE_METHOD1( Method3, m_method2and3Impl, void, const TCHAR* );
private:
Method1Impl m_method1Impl;
Method2and3Impl m_method2and3Impl;
};
void TestWeirdInterfaceImpl()
{
MyInterface* pItf = new InterfaceImpl();
pItf->Method1( 86 );
pItf->Method2( 42.0, 24.0 );
pItf->Method3( _T("hi") );
}
在C++之神为我们提供可变宏之前,您必须为您拥有的每个参数声明一个宏。此外,如果使用多重继承,可能不需要第二个"Obj"参数,但正如我之前所说,如果有另一个解决方案,我会避免多重继承,在本例中是一个额外的参数。
然而,第三种选择可能是《实用程序员》的作者们似乎非常提倡的。如果你有一大堆千篇一律的代码,你不想重复,因为正如你所指出的,它会引入人为错误。定义您自己的语言并编写代码生成器脚本(python、perl…(来自动创建实际代码。在这种情况下,您几乎可以指向一个接口,并让脚本为您写出文本。我自己还没有尝试过做这种事情,但最近我一直想在某个地方使用它,只是为了看看和评估结果。
这有点难看,可能会膨胀可执行文件的大小,但呢
#include <iostream>
class Interface
{
public:
virtual void method1() = 0;
virtual void method2(int x) = 0;
};
template<typename T>
class MethodOneImpl : public T
{
private:
void method1(int x)
{ std::cout << "MethodOneImpl::method1() " << x << std::endl; }
public:
void method1() { method1(0); }
};
template<typename T>
class MethodTwoImpl : public T
{
public:
void method2(int x)
{ std::cout << "MethodTwoImpl::myFunc(x)" << x << std::endl; }
};
class InterfaceImpl : public MethodTwoImpl<MethodOneImpl<Interface> >
{
};
int main()
{
InterfaceImpl impl;
impl.method1();
impl.method2(0);
}
class AbsInterface
{
// this is a simple interface class.
public:
virtual void Method1() = 0;
virtual void Method2() = 0;
};
class Functor1
{
public:
void operator () ()
{
printf("This Is Void Functor1");
}
};
class Functor2
{
public:
void operator () ()
{
printf("This Is void Functor2");
}
};
template <class T1, class T2>
class DerivedTemplateClass : public AbsInterface
{
public:
virtual void Method1() { T1()(); }
virtual void Method2() { T2()(); }
};
void main()
{
DerivedTemplateClass<Stratege1, Stratege2> instance;
instance.Method1();
instance.Method2();
}
正如你所看到的,我使用了Functor。您可以使用template和functor。
如果不让MethodOneImpl
/MethodTwoImpl
从Interface
继承,似乎不可能将它们带入Interface
的范围,因为如果不继承,它们将不会填充虚拟表。C++遗漏了其他语言中的关键字implements
。
因此,除非你意识到/接受你所寻找的只是一个桥接模式,它不满足要求a((你应该写更多的代码(,midly b((代码不一定很难维护(,并且可能满足c(,否则你就会陷入虚拟继承的困境。
这里(另一个(可能的解决方案(虽然只有减少膨胀的方法(
class Interface
{ public:
virtual void method1() {return impl_->method1();}
private:
Interface() {}
protected:
struct Impl {
virtual void method1() = 0; };
std::shared_ptr<Impl> impl_;
Interface(const std::shared_ptr<Impl> &impl) : impl_(impl) {}
};
class InterfaceImpl : public Interface
{
struct Impl : public Interface::Impl {
void method1() { std::cout << "InterfaceImpl::method1() " << std::endl; } } ;
public:
InterfaceImpl() : Interface(std::shared_ptr<Impl> (new Impl)) {}
};
template <class T>
class GenericInterfaceImpl : public Interface {
struct Impl : public Interface::Impl {
Impl( T &t) : t_(t) {}
void method1() { t_.method1() ; }
T t_; };
public:
GenericInterfaceImpl() : Interface(std::shared_ptr<Impl> (new Impl(T()))) {}
};
struct AMethod1Impl {
void method1() { std::cout << "AMethod1Impl::method1() " << std::endl; } } ;
struct AnotherMethod1Impl_not_working {
void method1_not_present() { std::cout << "AnotherMethod1Impl_not_working ::method1_not_present() " << std::endl; } } ;
int main() {
// compilation of next line would fail
// (lame attempt to simulate ompilation fail when pure function not implemented)
// Interface inf;
std::unique_ptr<Interface> inf;
inf.reset(new InterfaceImpl);
inf->method1();
inf.reset(new GenericInterfaceImpl<AMethod1Impl>() );
inf->method1();
// compilation of next line would fail
// inf.reset(new GenericInterfaceImpl<AnotherMethod1Impl_not_working>() );
}
这符合您的目的吗?它维护接口关系,并在不考虑客户端代码的情况下为您提供可维护的代码。
分离泛函中的每个方法,并赋予您控制不同基类的每个方法原型的权力。
#include <iostream>
#include <memory>
using namespace std;
//No Control over this.
class MethodOneImpl
{
private:
void method1(int x)
{ std::cout << "MethodOneImpl::method1() " << x << std::endl; }
public:
void method1() { method1(0); }
};
class MethodTwoImpl
{
public:
void myFunc(int x)
{ std::cout << "MethodTwoImpl::myFunc(x)" << x << std::endl; }
};
//*************************//
class Interface
{
public:
virtual void method1() = 0;
virtual void method2(int x) = 0;
};
//This is what i would do. //
class BaseFuncType
{
//no pure virtual
void Call()
{
throw "error";
}
void Call(int x)
{
throw "error";
}
};
class Method1: public BaseFuncType
{
auto_ptr<MethodOneImpl> MethodPtr;
public:
Method1()
{
MethodPtr.reset(new MethodOneImpl());
}
virtual int Call()
{
MethodPtr->method1();
}
};
class Method2: public BaseFuncType
{
auto_ptr<MethodTwoImpl> MethodPtr;
public:
Method2()
{
MethodPtr.reset(new MethodTwoImpl());
}
virtual int Call(int x)
{
MethodPtr->myFunc(x);
}
};
template <class T1>
class MethodFactory
{
private:
T1 methodObj;
public:
void CallMethod()
{
methodObj.Call();
}
void CallMethod(int x)
{
methodObj.Call(x);
}
};
class InterfaceImpl : public Interface
{
auto_ptr<MethodFactory> factory;
public:
virtual void method1()
{
factory.reset(new MethodFactory<Method1>());
factory->CallMethod();
}
virtual void method2(int x)
{
factory.reset(new MethodFactory<Method2>());
factory->CallMethod(x);
}
};
int main()
{
auto_ptr<Interface> inf;
inf.reset(new InterfaceImpl);
inf->method1();
inf->method2(10);
// This should be disallowed!
// std::unique_ptr<MethodOneImpl> moi;
// moi.reset(new InterfaceImpl);
}
- 用c++中的纯虚拟方法抽象模板类
- 我们可以在没有新实例化的情况下声明一个抽象方法来返回抽象超类中的子类对象吗
- C++ 多重继承:使用基类 A 的实现实现基类 B 的抽象方法
- c++ 中的抽象方法是否曾经调用过?
- C++在基类本身中重写基类的抽象方法
- C++使用*this从静态方法调用一个抽象方法
- 当后代需要不同的参数列表时,我应该如何在基类中定义抽象方法
- 我们可以通过在C++中的类中使用关键字“abstract”使所有方法抽象来声明接口类吗
- C++未解析的外部符号,在2个虚拟抽象方法上有50%的机会
- 调试数据方法 Q抽象表模型
- 从抽象类继承的抽象方法是否存在任何性能问题
- 从继承的类中实现抽象方法
- 在超类中调用抽象方法,并在C++中的子类中实现它
- 接口更改:为抽象c++方法添加新参数
- 类在c++中仍然是抽象的,即使模板类实现了抽象方法
- 使用其他基类的方法满足纯抽象方法的最简单方法是什么
- 使用指令和抽象方法
- 如何在可变上下文中使用抽象类时实现抽象方法
- 类中同时包含抽象方法和虚方法
- 在抽象类中调用抽象方法