0

I don't think that you can instantiate a class with an abstract function, but I'm not sure.

Furthermore, abstract functions are a way to define a contract, right? Since they must be implemented in the subclasses, by analogy like a contract.

Furthermore, I was also wondering if abstract functions can only have one implementation or multiple, and if they can exist in non-abstract classes. I I don't think that they can exist in non-abstract classes since an abstract functions means that a class is abstract, and I believe that abstract functions can have multiple implementations.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
Theo
  • 1
  • 3

1 Answers1

4

I don't think that you can instantiate a class with an abstract function, but I'm not sure.

No, you cannot.

Furthermore, I was also wondering if abstract functions can only have one implementation or multiple and if they can exist in non-abstract classes.

That's all of their purpuse. They can (silently) appear in a class hierarchy, with an abstract base and thus make derived classes abstract as well. But finally they must be implemented in a derived class that should be instantiatable.

I don't think that they can exist in non-abstract classes since an abstract functions means that a class is abstract and I believe that abstract functions can have multiple implementations.

A pure virtual function (no matter if inherited or directly declared) is what makes the class abstract.


As you mentioned contracts:

A pure virtual funciton can be considered as a contract, yes.

In c++ they are usually used to declare interfaces like follows

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 can inherit multiple interfaces, which other classes can use as contracts, without the need to know the concrete class which implements it.

 // 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;
 };


Another way is, to use them in a Template Method design. I.e. an abstrct class, which has an algorithm or some behavior implemented, and relies on inheriting classes to implement an essential part of it.

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;
};
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • @Theo No it can have as many implementations as you want in a whole bunch of inherited classes. As mentioned that's the purpose. I've edited my answer a bit for clarity. But all in all it's a broad field, and used in all kinds of software designs. – πάντα ῥεῖ Oct 09 '20 at 19:39
  • @Theo You see, it's a long answer, and that's only the tip of the iceberg. – πάντα ῥεῖ Oct 09 '20 at 20:02
  • @Pete Well, you're right, implementation can be postponed in the class hierarchy. I'll try to fix that sentence. Ty. – πάντα ῥεῖ Oct 09 '20 at 21:00
  • @Pete Better now? – πάντα ῥεῖ Oct 09 '20 at 21:05
  • Also note that a pure virtual (abstract) method can have a default implementation in the abstract class that declares it. For a pure virtual, an implementation in the declaring class is optional, but an overriding implementation in a derived non-abstract class is required. – Remy Lebeau Oct 09 '20 at 21:09
  • @Remy I know that, but that surely would confuse the OP even more ;-). You can point that out in another answer. Especially for the destructor defintions that's a helpful thiing, because it forces the inheriting classes to implment a virtual destructor as well, without letting the linker be confused of a missing definiton. – πάντα ῥεῖ Oct 09 '20 at 21:11