首页 > 解决方案 > 抽象函数(C++ 中的纯虚函数)可以阻止该类的实例化吗?它们是定义合约的一种方式吗?

问题描述

我不认为你可以用抽象函数实例化一个类,但我不确定。

此外,抽象函数是定义合约的一种方式,对吧?因为它们必须在子类中实现,类比合同。

此外,我还想知道抽象函数是否只能有一个或多个实现,以及它们是否可以存在于非抽象类中。我不认为它们可以存在于非抽象类中,因为抽象函数意味着一个类是抽象的,我相信抽象函数可以有多个实现。

标签: c++abstract-classvirtual

解决方案


我不认为你可以用抽象函数实例化一个类,但我不确定。

你不能。

此外,我还想知道抽象函数是否只能有一个或多个实现,以及它们是否可以存在于非抽象类中。

这就是他们的全部目的。它们可以(无声地)出现在类层次结构中,具有抽象基础,因此也可以使派生类抽象。但最后它们必须在应该可实例化的派生类中实现。

我不认为它们可以存在于非抽象类中,因为抽象函数意味着一个类是抽象的,我相信抽象函数可以有多个实现。

纯虚函数(无论是继承的还是直接声明的)使类抽象的原因。


正如你提到的合同

一个纯粹的虚拟功能可以被认为是一个合同,是的。

在 c++ 中,它们通常用于声明如下接口

struct IMyInterface {
     virtual void foo(int a, std::string b) = 0;
     virtual int bar() = 0;
     virtual ~IMyInterface() {}; // Note: Interfaces must have at least a 
                                 // virtual destructor function defined, but 
                                 // no other non pure virtual funcitons must 
                                 // be implemented.
};

一个类可以继承多个接口,其他类可以将其用作契约,而无需知道实现它的具体类。

 // A class implementing the interface
 class Baz : public IMyInterface {
     
     virtual void foo(int a, std::string b) {
          // Do something with a and b
          // ...
     }
     virtual int bar() {
          return 3 * 5;         
     }
     virtual ~Baz() = default; // Default destructors aren't automatically virtual!
 };

 // Another class implementing the interface
 class Twiddle : public IMyInterface {
     
     virtual void foo(int a, std::string b) {
          // Do something with a and b
          // ...
     }
     virtual int bar() {
          return 42;
     }
     virtual ~Twiddle() = default;
 };

 // A class using the interface
 class Client {
 public:
     // The concrete implementation can be configured by passing 
     // the interface in the vonstructor
     Client(IMyInterface* intf_) : intf(intf_) {}
     void someMethod() {
         intf->foo(42,"Hello universe!");
         int x = intf->bar();
     }
 private:
     IMyInterface* intf;
 };


另一种方法是,在模板方法设计中使用它们。即一个抽象类,它实现了算法或某些行为,并依赖于继承类来实现它的基本部分。

class MyAbstractBase {
protected:
    struct context {
        int paramA;
        std::string paramB;
    };
    int operateOnContext(const context& ctx) = 0;
public:
    // Some behavior exposed to client classes
    int doSomething() {
        // Setup a context
        context ctx { 42, "Hello universe!" };
        return operateOnConetxt(ctx);
    }
    virtual ~MyAbstractBase() = default;
};

// An inherited class, which will write the context to a file
class Derived1 : public MyAbstractBase {
protected:
     int operateOnContext(const MyAbstractBase::context& ctx) {
         std::ofstream out("AFile.txt");
         out << "Param A is:" << ctx.paramA << std::endl;
         out << "Param B is:" << ctx.paramB << std::endl;
     }
public:
    virtual ~Derived1() = default;
};

// Another inherited class, which will send the context over a network connection
class Derived2 : public MyAbstractBase {
protected:
     int operateOnContext(const MyAbstractBase::context& ctx) {
         NetworkConn conn;
         conn.connect("NetworkEndpoint");
         conn.send(ctx.paramA);
         conn.send(ctx.paramB);
         conn.disconnect();
     }
public:
    virtual ~Derived2() = default;
};

推荐阅读