如何在C++中编程接口/抽象类? 请考虑这样的纯虚拟类: class Foo { public: virtual int FooBar() = 0; };
Java开发人员会将这种东西称为接口。通常情况下,您会编程到该接口,例如,坏示例,抱歉:如何在C++中编程接口/抽象类? 请考虑这样的纯虚拟类: class Foo { public: virtual int FooBar() = 0; };,c++,interface,abstract-class,C++,Interface,Abstract Class,Java开发人员会将这种东西称为接口。通常情况下,您会编程到该接口,例如,坏示例,抱歉: class Bar { public: Foo f; }; class Child : public Foo { public: int FooBar() { return 1; } }; Bar b; b.foo = Child(); 这显然在C++中不起作用,因为类FO的实例是在构造时创建的,但这是不可能的,因为FoO是抽象类。 < C++ > 中的接口是否有编程模式? 编辑:澄清
class Bar {
public: Foo f;
};
class Child : public Foo {
public: int FooBar() { return 1; }
};
Bar b;
b.foo = Child();
这显然在C++中不起作用,因为类FO的实例是在构造时创建的,但这是不可能的,因为FoO是抽象类。 < C++ >
中的接口是否有编程模式?编辑:澄清了示例,对不起。我认为您需要继承接口,而不是使用组合,不是吗 像这样
class Bar: public Foo
{
private:
virtual int Bar() { /* ... */ }
};
这就是我从程序到接口的理解
class IFoo
{
public:
// enable deletion of implementation classes through IFoo*
virtual ~IFoo() {}
// interface
void bar()
{
// add optional pre-processing here
do_bar();
// add optional post-processing here
}
private:
// to be overridden by implementation classes
virtual void do_bar() = 0; // pure virtual
// no state here!
};
class FooImpl
:
public IFoo
{
public:
// constructors, assignment etc. to manipulate state
private:
virtual void do_bar()
{
// your implementation
}
// add your state here
};
void my_algorithm(IFoo* foo)
{
foo->bar();
}
int main()
{
IFoo* f = new FooImpl();
my_algorithm(f); // resolves to using FooImpl::do_bar()
return 0;
}
编辑:啊哈,看看你的编辑,你真的需要这里的指针。下面是等效的C++代码:
class Foo {
public: virtual int Bar() = 0;
};
class Bar {
//.........v
public: Foo* f;
};
class Child : public Foo {
public: int Bar() { return 1; }
};
Bar b;
b.f = new Child();
但接下来,您需要为孩子处理新分配的内存。为了避免这种情况并使代码在逻辑上完全等效,您需要智能指针,在这种情况下-一个共享的ptr,我认为您需要继承接口,而不是使用组合,不是吗 像这样
class Bar: public Foo
{
private:
virtual int Bar() { /* ... */ }
};
这就是我从程序到接口的理解
class IFoo
{
public:
// enable deletion of implementation classes through IFoo*
virtual ~IFoo() {}
// interface
void bar()
{
// add optional pre-processing here
do_bar();
// add optional post-processing here
}
private:
// to be overridden by implementation classes
virtual void do_bar() = 0; // pure virtual
// no state here!
};
class FooImpl
:
public IFoo
{
public:
// constructors, assignment etc. to manipulate state
private:
virtual void do_bar()
{
// your implementation
}
// add your state here
};
void my_algorithm(IFoo* foo)
{
foo->bar();
}
int main()
{
IFoo* f = new FooImpl();
my_algorithm(f); // resolves to using FooImpl::do_bar()
return 0;
}
编辑:啊哈,看看你的编辑,你真的需要这里的指针。下面是等效的C++代码:
class Foo {
public: virtual int Bar() = 0;
};
class Bar {
//.........v
public: Foo* f;
};
class Child : public Foo {
public: int Bar() { return 1; }
};
Bar b;
b.f = new Child();
但接下来,您需要为孩子处理新分配的内存。为了避免这种情况并使代码在逻辑上完全等效,您需要智能指针,在这种情况下-一个共享的ptr,除了一个例外,您做的一切都是正确的。您需要从接口派生,而不是将其作为成员包含
class myInterface
{
virtual void foo() = 0;
}
class iHaveAnInterface: public myInterface
{
void foo();
}
void iHaveAnInterface::foo()
{
//implement
}
你做的每件事都是对的,只有一个例外。您需要从接口派生,而不是将其作为成员包含
class myInterface
{
virtual void foo() = 0;
}
class iHaveAnInterface: public myInterface
{
void foo();
}
void iHaveAnInterface::foo()
{
//implement
}
如果需要指向或引用接口或抽象类的实现的内容,可以使用指向该接口的引用指针:
class Bar {
public:
Bar( Foo& af ) : f( af )
{}
private:
Foo& f;
};
如果要使用引用Foo&f,则指针Foo*f或指向const Foo*f的const实现const Foo&f的引用或指针,甚至指向const实现const Foo*const f的const指针都取决于您的需求
如果可能的话,对于从外部传递引用实现的组合,使用引用,如我的示例中所示。如果对象更像是聚合,并且由包含对象本身构造,请使用指针或智能指针
更新:
到目前为止,没有人提到过,如果要动态分配实现接口的对象,基类必须有一个虚拟析构函数,否则即使使用智能指针,也会调用未定义的行为。要注意,智能指针可能很方便,但它们并不是万能的。您仍应记住某些所有者层次结构,否则最终会出现无法通过智能指针轻松解决的循环。如果您需要指向或引用接口或抽象类实现的内容,可以使用指向该接口的引用指针:
class Bar {
public:
Bar( Foo& af ) : f( af )
{}
private:
Foo& f;
};
如果要使用引用Foo&f,则指针Foo*f或指向const Foo*f的const实现const Foo&f的引用或指针,甚至指向const实现const Foo*const f的const指针都取决于您的需求
如果可能的话,对于从外部传递引用实现的组合,使用引用,如我的示例中所示。如果对象更像是聚合,并且由包含对象本身构造,请使用指针或智能指针
更新:
到目前为止,没有人提到过,如果要动态分配实现接口的对象,基类必须有一个虚拟析构函数,否则即使使用智能指针,也会调用未定义的行为。要注意,智能指针可能很方便,但它们并不是万能的。您仍应记住某些所有者层次结构,否则最终会出现无法通过智能指针轻松解决的循环。您的数据成员f应声明为指向Foo的指针,或者更好地声明为指向Foo的某种形式的智能指针,例如共享\u ptr
您可以使用对Foo的引用,但这会使事情复杂化:您的类需要一个显式构造函数,并且除非您显式实现两个成员函数,否则不可复制或分配。您的数据成员f应该声明为指向Foo的指针,或者更好的是,声明为指向Foo的某种形式的智能指针,例如shared\u ptr
您可以使用对Foo的引用,但这会使事情复杂化:您的类需要一个显式构造函数,并且除非您显式地实现两个成员函数,否则不可复制或分配。为了像在Java中一样使用多态性,您需要像在Java中一样使用指针和引用。在Java中,一切都是基元类型或引用:当您编写Foo f时;在Java中,您可以获得一个引用。在C++中,你得到一个对象。
但是,与java不同,C++中的接口不必涉及vi。
RTU函数和基类。一个很好的例子是在标准库中使用的迭代器接口。为了像在Java中一样使用多态性,您需要像在Java中一样使用指针和引用。在Java中,一切都是基元类型或引用:当您编写Foo f时;在Java中,您可以获得一个引用。在C++中,你得到一个对象。
但是,与java不同,C++中的接口不必涉及虚拟函数和基类。一个很好的例子是标准库中使用的迭代器接口。C++中的
接口最好是作为抽象基类编写的:至少包含一个纯虚函数的无状态类。具体类从接口类公开派生,并可选地添加状态以实现接口
class IFoo
{
public:
// enable deletion of implementation classes through IFoo*
virtual ~IFoo() {}
// interface
void bar()
{
// add optional pre-processing here
do_bar();
// add optional post-processing here
}
private:
// to be overridden by implementation classes
virtual void do_bar() = 0; // pure virtual
// no state here!
};
class FooImpl
:
public IFoo
{
public:
// constructors, assignment etc. to manipulate state
private:
virtual void do_bar()
{
// your implementation
}
// add your state here
};
void my_algorithm(IFoo* foo)
{
foo->bar();
}
int main()
{
IFoo* f = new FooImpl();
my_algorithm(f); // resolves to using FooImpl::do_bar()
return 0;
}
上面的代码是关于运行时多态性和显式接口的。在C++中有一个使用编译时多态和隐式接口的替代方案。这是使用模板和奇怪的重复模板模式完成的
注意,我在这里使用了非虚拟接口NVI习惯用法:IFoo的公共接口是非虚拟的,实现是纯虚拟的。这给接口的编写者提供了更多的灵活性,例如在没有客户端注意的IfO::BAR等中添加日志记录和其他检查。C++中的< P>接口最好是作为抽象基类编写的:至少包含一个纯虚函数的无状态类。具体类从接口类公开派生,并可选地添加状态以实现接口
class IFoo
{
public:
// enable deletion of implementation classes through IFoo*
virtual ~IFoo() {}
// interface
void bar()
{
// add optional pre-processing here
do_bar();
// add optional post-processing here
}
private:
// to be overridden by implementation classes
virtual void do_bar() = 0; // pure virtual
// no state here!
};
class FooImpl
:
public IFoo
{
public:
// constructors, assignment etc. to manipulate state
private:
virtual void do_bar()
{
// your implementation
}
// add your state here
};
void my_algorithm(IFoo* foo)
{
foo->bar();
}
int main()
{
IFoo* f = new FooImpl();
my_algorithm(f); // resolves to using FooImpl::do_bar()
return 0;
}
上面的代码是关于运行时多态性和显式接口的。在C++中有一个使用编译时多态和隐式接口的替代方案。这是使用模板和奇怪的重复模板模式完成的
注意,我在这里使用了非虚拟接口NVI习惯用法:IFoo的公共接口是非虚拟的,实现是纯虚拟的。这为接口编写者提供了更大的灵活性,例如在IFoo::bar等内部添加日志记录和其他检查,而客户端没有注意到。java开发人员不会这样做,他会使用implements关键字来实现接口。不将其声明为类成员。代码示例仍然很糟糕,在Java中也不起作用,因为Bar不是Child的基类。Java开发人员不会这样做,他会使用implements关键字来实现接口。不将其声明为类成员。代码示例仍然很糟糕,在Java中也不起作用,因为Bar不是Child的基类。您的示例如下所示:成员f是引用而不是对象,构造函数还传递了对Foo或任何子类实例的引用,位faf将该引用存储在成员变量f中-是否正确?@Niko-这很危险,小心。在这种情况下,不能执行以下操作:b.f=Child;,因为Child将创建一个临时对象,所以b.f将是对该临时对象的引用,并且正好在该临时对象之后;在这一排,孩子将被毁灭!然后,你将有一个无效的引用,因此,未定义的行为。@原因的KILIKIROV,你必须知道你想做什么,这对于C++是特别真实的。由于f是私有的,分配将不起作用,如果f是公共的,则b.f=子对象;将子实例切片为一个Foo,并使用操作符=constfoo&将Temp分配给f。因此,没有危险。您的示例如下:成员f是一个引用而不是一个对象,构造函数还被传递一个对Foo或任何子类的引用,位faf将此引用存储在成员变量f中-是否正确?@Niko-这很危险,小心。在这种情况下,不能执行以下操作:b.f=Child;,因为Child将创建一个临时对象,所以b.f将是对该临时对象的引用,并且正好在该临时对象之后;在这一排,孩子将被毁灭!然后,你将有一个无效的引用,因此,未定义的行为。@原因的KILIKIROV,你必须知道你想做什么,这对于C++是特别真实的。由于f是私有的,分配将不起作用,如果f是公共的,则b.f=子对象;将子实例切片为一个Foo,并使用操作符=constfoo&将Temp分配给f。所以,没有危险。请检查您的标准库是否支持共享\u ptr。如果没有,您需要检查您的标准库是否支持共享\u ptr。如果不是,你需要