Here's what I have found so far, organized by C++ feature. I won't pretend that this comparison is either complete or completely accurate. As noted elsewhere, this discussion is based on IBM's implementation, mostly for mainframes. IBM has apparently implemented only a subset of the draft COBOL standard.
All classes inherit, directly or indirectly, from SOMObject. A class is itself an object instance of SOMClass. For special purposes you can define a metaclass derived from SOMClass.
Since data members are not visible to the client code of a class (see below), the compiler doesn't need to know the size of the objects it uses. It merely needs to mangle the names of the methods so that the linker can look for the right routines.
However, the classes used by a program must be declared in the CONFIGURATION SECTION, in a special REPOSITORY paragraph.
IBM stores interface information in a special database called an IR (Interface Repository). The compiler may optionally consult the IR to enforce proper use of the classes described there. The IR plays roughly the same role as C++ header files, providing the equivalent of function prototypes for methods.
In C++ you would typically use private inheritance to represent a "has-a" or "is-implemented-as" relationship. Class Derived would inherit privately from Base. In OO COBOL, your best bet is to embed an object reference to a Base as a data member of Derived.
OO COBOL supports multiple inheritance. As with C++, there are rules for resolving conflicts among methods inherited from more than one parent class.
All data members are private; i.e. they are accessible only to the methods of that class.
All methods are virtual and public.
You don't CALL a method -- you INVOKE it. As with a CALL, you may specify a method with either a literal (for static linkage) or a data name (for dynamic linkage).
As with C++, the method invoked at run time depends on the type of the object referenced. If you invoke a method through a reference to a base class, but the reference refers to an object of a derived class, you'll invoke the method associated with the derived class, not the one associated with the base class.
If you really need something like an abstract base class, you can build some clumsy checks to prevent the class from being instantiated. The constructor (see below) can interrogate the class for run-time type information, and abend if the object does not belong to a derived class. However there is no way to prevent instantiation at compile time.
COBOL object references occupy a middle ground between pointers and references as we know them in C++.
Unlike a reference in C++, an object reference in OO COBOL can be NULL, or it may be reseated from one object to another, or to NULL. Unlike a pointer, you cannot dereference an object reference. You can use an object reference only to specify an object instance whose method you wish to invoke.
As with pointers, multiple object references may refer to the same instance.
Object references may be either typed or untyped. An untyped reference may refer to any object. A typed reference may refer only to an object of the designated class, or of a class derived from it.
Likewise the somFree method corresponds to operator delete.
You cannot allocate arrays of objects, so you don't need equivalents to operators new[] or delete[]. You can declare an array of object references and allocate each instance separately.
somNew and somFree are methods of SOMClass (a generic class of classes). Theoretically, if you define your own metaclass, you could override them with your own versions of somNew and somFree, just as you might override operators new and delete in C++. However, SOM is presumably not bound by COBOL's restrictions. It may not be possible to override these methods. I haven't tried it yet.
C++ calls a constructor whenever an object is created, and a destructor whenever the object is destroyed. Likewise, someNew invokes somInit whenever it allocates an object, and somFree invokes somUninit.
As with C++, OO COBOL invokes the constructor of a base class before invoking the constructor of the derived class. Likewise it invokes the destructor of the base class after invoking the destructor of the derived class. (I couldn't find anything in the manual that said so, but I did some experimenting.)
Like a default constructor in C++, somInit takes no parameters. There's no way to overload somInit with a parameterized constructor. The manual recommends that you define a metaclass with a parameterized method for creating an object. However, this approach offers no evident advantages over an ordinary subprogram.
There are several ways to approximate static members:
Suppose, for example, you want to maintain a counter of all the instances of a class. You want to increment it whenever you allocate an instance, and decrement it whenever you deallocate. How do you enforce the proper maintenance of such a counter?
You could increment the counter in somInit, and decrement it in somUninit. However, there's no way to make the counter accessible to both methods without making it accessible to every routine in the load module.
You could bury the counter in a metaclass or a subprogram, and provide special methods or entry points for allocating and deallocating objects. However, you can't prevent the client code from calling somNew or somFree directly, bypassing the counter maintenance.
This inability to declare static members is a crippling weakness in IBM's implementation.