如何在C++中编程接口/抽象类? 请考虑这样的纯虚拟类: class Foo { public: virtual int FooBar() = 0; };

如何在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++ > 中的接口是否有编程模式? 编辑:澄清

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
{
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。如果不是,你需要