c++接口和虚函数与Java接口的比较

Interface and virtual functions in C++ compared to Java interface

本文关键字:接口 Java 比较 函数 c++      更新时间:2023-10-16

我有一个关于c++虚函数的问题。virtual关键字在c++ class声明中用于基类中的函数,以便通知该函数的子类实现可能因子类而异。不同的子类可以有不同的函数实现。

我一点也不明白。当你在c++中定义接口时,就我目前所见,它与Java不同。

事实上,我不明白c++中的接口是什么意思。在头文件中指定一个函数为virtual。然后子类或基类的派生类可以以任何方式覆盖它,只要它是一个虚函数。

c++中的接口是头文件吗?

Cheers

Interface在Java中是一个特定的语言结构或关键字。Java有一个关键字interface,用于表示Java类不提供实际实现,而是描述派生类必须实现的接口。这是由Java编译器检查的,以确保声明实现接口的类为接口提供了所有必要的方法。

在Java中,interface关键字表示一个类提供了一组由指定的接口类描述的服务。一个Java类可以实现多个不同的接口。

在与c++的讨论中使用"接口"一词的方式是一个有点类似的概念,因为它与类、函数或方法的参数类型有关。然而,c++中没有interface关键字。"接口"一词在c++中以一种更通用的、描述性的方式使用,如"函数接口有两个短接口和一个长接口",它表示函数调用参数及其类型,函数调用者和函数体之间的接口。

所以把c++中的接口看作是实现接口的类和使用从类实例化的对象的任何对象之间的一种契约。一个类实际上也可以提供几个不同的相关服务,每个服务都有一个特定的接口。

可以在c++中通过在类描述中使用纯虚方法来创建抽象类,从而实现类似于Java interface的概念。这将创建一个没有实现的c++类。参见c++:用抽象方法创建抽象类,并在子类中重写该方法。

虚方法的作用是提供一种机制,使使用类的派生类的对象可以依赖于特定的接口,而将实现的细节留给派生类。这类似于Java接口。c++虚方法提供了一种使用编译和静态检查方法而不是运行时方法实现Java接口的方法。

使用虚方法,您可以创建一个超类类型,该超类类型可用于创建指针变量,这些指针变量可以从派生类型中分配变量,并且当您使用虚方法时,将调用派生类中的正确方法。确定要调用哪个方法是在编译时而不是运行时完成的。c++的主要思想是像C一样高效,同时提供面向对象的语言结构以及编译时的静态类型检查,以减少对运行时错误检测的依赖以及它的额外开销。

class Joe {
public:
virtual int thingOne() { return 1;}  // standard, not pure virtual method
..
};
class JoeTwo : public Joe {
public:
int thingOne() { return 2;}   // derived class provides its own version of the method
..
};
Joe *myJoe = new JoeTwo;
int i = myJoe->thingOne();  // value of 2 put into i and not value of 1

在c++中,由于对象切片,当包含派生对象的变量赋值给包含派生对象超类的变量时,可能会发生对象切片,因此您需要识别对象和指向对象的指针之间的区别。这种"对象切片"会发生,因为派生对象不适合它派生的基类或超类对象。派生对象具有超类对象所没有的附加内容,因此在赋值时(默认赋值是直接内存复制),只有派生对象的超类部分被复制到超类对象中。

class Joe {
public:
virtual int thingOne() { return 1;}  // standard, not pure virtual method
..
};
class JoeTwo : public Joe {
public:
int thingOne() { return 2;}   // derived class provides its own version of the method
..
};
Joe *myJoe = new JoeTwo;    // no object slicing since this is pointer
JoeTwo myJoeTwo;
Joe  myJoeSliced = myJoeTwo;  // JoeTwo object myJoeTwo sliced to fit into Joe object myJoeSliced

Java和c++的主要区别在于Java中的每个函数都是virtual

从历史上看,当开发c++时,在每个函数调用之间放置一个抽象层(这是使用虚方法表时发生的事情)并不是每个方法调用都想要的,因为虚方法调用更慢。

因此,您必须指定必须通过动态绑定调用方法,否则在编译时根据变量的声明选择该方法。这意味着如果你声明了Base *b = new Derived(),而你在b上调用了一个非虚的方法,那么这个方法在编译时被选择,它将是一个Base::method

座右铭是你不用为你不用的东西付钱就是这样。

c++中的

接口是不存在的,但是你可以有一个只有纯虚函数的类,它们的行为基本相同。实际上你可以有两种虚拟方法:

class Base {
  virtual void method() {
    //implementation
  }
  virtual void pureMethod() = 0;
}

首先method()是虚拟的,服从动态绑定,但它是在基类中实现的,而pureMethod()仍然服从动态绑定,但它被声明为纯虚拟的,所以它没有任何实现,因此Base不能被实例化,因为它是,你需要子类化它,并覆盖至少纯虚拟方法。

c++没有像Java那样的接口。最接近的情况是,当您定义一个只有纯虚函数的类时,从该类派生的每个人都被迫实现所有虚函数。

c++中的虚方法是可以被重写的方法。纯虚方法(定义为virtual foo() = 0)是抽象方法。要创建类似于Java中使用的接口,只需指定所有方法都是纯虚的(抽象的)。

然而,有时"接口"指的是类的公共成员和类型,通常完全在头文件中。

c++类的接口在头文件中定义。虚函数仅在想要子类化并使用继承时使用。

在c++中,最接近java的接口是当你使用纯抽象类的时候。实现具有此接口的类必须继承此抽象类。

不要忘记将解构函数设置为虚函数,否则在引用基类时不会调用子类的解构函数。

的例子:

class PuppetInterface
{
public:
    virtual ~PuppetInterface() {};
    virtual void walk() = 0;
    virtual void tellALie() = 0;
};
class Pinocchio : public PuppetInterface
{
public:
    ~Pinocchio()
    {
        //lie down look dead.
    }
    void walk()
    {
        //try moving wooden legs.
    }
    void tellALie()
    {
        //let nose grow look serious.
    }
};
int main(int argc, const char * argv[])
{
    PuppetInterface* pinocchio = new Pinocchio();
    pinocchio->walk();
    pinocchio->tellALie();
    delete pinocchio;
    return 0;
}

编辑:由于原始指针是坏的,不例外保存,可能泄漏等。上面的代码应该重写为

//using c++ 11
int main(int argc, const char * argv[])  
{
    auto pinocchio = std::unique_ptr<PuppetInterface>(new Pinocchio());
    pinocchio->walk();
    pinocchio->tellALie();  
 }