4

In Java it's possible to write an abstract, super class with unimplemented, abstract methods and non-abstract methods which invoke the abstract methods. Then in the subclass are the abstract methods implemented. When you then make an instance of the subclass, the super class uses the implementations in the subclass. How do I accomplish this in C++?

Here is what I mean, but in Java:

SuperClass.java

public abstract class SuperClass {

    public SuperClass() {
        method();
    }

    private void method() {
        unimplementedMethod();
    }

    protected abstract void unimplementedMethod();
}

SubClass.java

public class SubClass extends SuperClass {

    public SubClass() {
        super();
    }

    @Override
    protected void unimplementedMethod() {
        System.out.println("print");
    }

    public static void main(String[] args) {
        new SubClass();
    }
}

Would be awesome if you showed me how this is accomplished in C++. :)

Daniel Jonsson
  • 3,261
  • 5
  • 45
  • 66
  • If you are curious, what you are implementing is actually a reasonably common design pattern. If I have the right pattern in mind, this is called the Template Method pattern: http://en.wikipedia.org/wiki/Template_method_pattern – Ed Carrel Feb 13 '12 at 22:11

5 Answers5

4

In general, what you are looking for, is the virtual keyword. In a nutshell virtual declares the intent that this method can be overriden. Note that such a method can still have an implementation- virtual just makes it overrideable. To declare an "abstract method", you can say declare intent of please provide an implementation in the derived class with = 0, as shown below. Such methods are called pure virtual in C++.

However, there are some caveats that you should watch out for. As pointed out in a comment below, you were calling method() from within the SuperClass constructor. Unfortunately this is not possible in C++, due to the order in which objects are constructed.

In C++ a derived class constructor immediately calls it's superclass constructor before allocating its members or executing the body of the constructor. As such, the members of the base class are constructed first, and the derived class' members are constructed last. Calling a virtual method from a base class will not work as you expect in Java, since the derived class has not been constructed yet, and thus the virtual methods have not been redirected to the derived implementations yet. Hope that makes sense.

However, calling method() on a SuperClass object after creation will work as you expect: it would call the virtual function which would output "print".

class SuperClass {

public:
    SuperClass() {
        // cannot call virtual functions from base constructor.
    }
    virtual ~SuperClass() { } // destructor. as Kerrek mentions,
                               // classes that will be inherited from,
                               // should always have virtual destructors.
                               // This allows the destructors of derived classes
                               // to be called when the base is destroyed.

private:
    void method() {
        unimplementedMethod();
    }

protected:
    virtual void unimplementedMethod() = 0; // makes method pure virtual,
                                            // to be implemented in subclass
}

SubClass.h

class SubClass : public SuperClass {

public:
    SubClass() : SuperClass() { // how the superclass constructor is called.

    }

    // no need for "override" keyword, if the methd has the same name, it will
    // automatically override that method from the superclass
protected:
    void unimplementedMethod() { 
        std::cout << "print" << std::endl;
    }
}
Alexander Kondratskiy
  • 4,156
  • 2
  • 30
  • 51
3

In C++, you should never call virtual functions in the constructor, so it doesn't work quite as literally. Best to use a separate member function

class SuperClass
{
public:
    void action() { method(); }   // not in the constructor, please
    virtual ~SuperClass() { }     // always a virtual destructor when polymorphic

protected:
    void method() { unimplementedMethod(); }

private:
    virtual void unimplementedMethod() = 0;
};

class SubClass : public SuperClass
{
private:
    virtual void unimplementedMethod() { std::cout << "print" << std::endl; }

// no need to spell out the next couple of functions, but for your entertainment only
public:
    SubClass() : SuperClass() { }
    virtual ~SubClass() { }
};

Now to invoke:

int main()
{
    SuperClass * p = new SubClass; // construct first...
    p->action();                   // ... then invoke, after construction is complete

    delete p;                      // thank god for that virtual destructor!
}

The base constructor runs before the derived class is constructed, so you cannot call any derived functions in the base constructor, and in particular you cannot call any pure-virtual functions.

Note that you have the private and protected the wrong way round: The non-virtual accessor function should be protected so it can be used in the entire class hierarchy, but the virtual implementation function should be private, since it only needs to be seen by the accessor function in the same class. In a nutshell: protected-nonvirtual and private-virtuals.

(The usage example is a bit contrived, since you wouldn't normally use new or raw pointers in C++.)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
1

In C++ these are called pure virtual functions/methods.

Basically you tack a "=0" at the end of a method:

virtual doSomething() = 0; // pure virtual

Search around SO for "c++ pure virtual" and you'll find tons of answers.

NuSkooler
  • 5,391
  • 1
  • 34
  • 58
1

You need to use virtual methods. The implementation works like this:

/* here's MyBaseClass.h */
class MyBaseClass
{
public:
    MyBaseClass(void);
    ~MyBaseClass(void);

    void MyMethod();

protected:
    virtual void MyUnimplementedMethod() = 0;
};


/* here's MyIneritedClass.h */
class MyInheritedClass :
    public MyBaseClass
{
public:
    MyInheritedClass(void);
    ~MyInheritedClass(void);

protected:
    virtual void MyUnimplementedMethod();
};


/* here's the implementation of the method in the base class */
void MyBaseClass::MyMethod()
{
    MyUnimplementedMethod();
}


/* and here's the implementation of the abstract method in the derived */
void MyInheritedClass::MyUnimplementedMethod()
{
    _tprintf(L"Hello, world");
}
0

You declare the method as virtual:

snippet:

class Parent{
public:
    virtual int methodA() {return methodB();}; // calls the abstract method
    virtual int methodB() = 0; // "=0" means pure virtual, not implemented in the base
}

class Child : public Parent{
public:
    virtual int methodB() { /* implementation */}
}

virtual means the child may override the implementation and the parent should be then calling the overriden implementation. Adding "=0" to the declaration of the virtual method makes it pure virtual, i.e.: the base doesn't have an implementation of its own, and relies on the implementation by the child. Such class cannot be instantiated (i.e.: abstract class).

littleadv
  • 20,100
  • 2
  • 36
  • 50
  • A pure virtual function can have an implementation, i. e. a body, even though it usually doesn't. You might need it to provide a default implementation that can be called from the subclass. – Dima Feb 13 '12 at 22:10