mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-30 23:21:04 +00:00
docs: Update HowToSetUpLLVMStyleRTTI.
Recent changes to isa<>/dyn_cast<> have made unnecessary those classof() of the form: static bool classof(const Foo *) { return true; } Accordingly, remove mention of such classof() from the documentation. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@165766 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
8b8fa7b2f4
commit
8a6538cd61
@ -174,8 +174,6 @@ steps:
|
||||
|
||||
Shape(ShapeKind K) : Kind(K) {}
|
||||
virtual double computeArea() = 0;
|
||||
+
|
||||
+ static bool classof(const Shape *) { return true; }
|
||||
};
|
||||
|
||||
class Square : public Shape {
|
||||
@ -184,7 +182,6 @@ steps:
|
||||
Square(double S) : Shape(SquareKind), SideLength(S) {}
|
||||
double computeArea() /* override */;
|
||||
+
|
||||
+ static bool classof(const Square *) { return true; }
|
||||
+ static bool classof(const Shape *S) {
|
||||
+ return S->getKind() == SquareKind;
|
||||
+ }
|
||||
@ -196,31 +193,43 @@ steps:
|
||||
Circle(double R) : Shape(CircleKind), Radius(R) {}
|
||||
double computeArea() /* override */;
|
||||
+
|
||||
+ static bool classof(const Circle *) { return true; }
|
||||
+ static bool classof(const Shape *S) {
|
||||
+ return S->getKind() == CircleKind;
|
||||
+ }
|
||||
};
|
||||
|
||||
Basically, the job of ``classof`` is to return ``true`` if its argument
|
||||
is of the enclosing class's type. As you can see, there are two general
|
||||
overloads of ``classof`` in use here.
|
||||
The job of ``classof`` is to dynamically determine whether an object of
|
||||
a base class is in fact of a particular derived class. The argument to
|
||||
``classof`` should always be an *ancestor* class because the
|
||||
implementation has logic to allow and optimize away
|
||||
upcasts/up-``isa<>``'s automatically. It is as though every class
|
||||
``Foo`` automatically has a ``classof`` like:
|
||||
|
||||
#. The first, which just returns ``true``, means that if we know that the
|
||||
argument of the cast is of the enclosing type *at compile time*, then
|
||||
we don't need to bother to check anything since we already know that
|
||||
the type is convertible. This is an optimization for the case that we
|
||||
statically know the conversion is OK.
|
||||
.. code-block:: c++
|
||||
|
||||
#. The other overload takes a pointer to an object of the base of the
|
||||
class hierarchy: this is the "general case" of the cast. We need to
|
||||
check the ``Kind`` to dynamically decide if the argument is of (or
|
||||
derived from) the enclosing type.
|
||||
class Foo {
|
||||
[...]
|
||||
static bool classof(const Foo *) { return true; }
|
||||
[...]
|
||||
};
|
||||
|
||||
To be more precise, let ``classof`` be inside a class ``C``. Then the
|
||||
contract for ``classof`` is "return ``true`` if the argument is-a
|
||||
``C``". As long as your implementation fulfills this contract, you can
|
||||
tweak and optimize it as much as you want.
|
||||
In order to downcast a type ``Base`` to a type ``Derived``, there needs
|
||||
to be a ``classof`` in ``Derived`` which will accept an object of type
|
||||
``Base``.
|
||||
|
||||
To be concrete, in the following code:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
Shape *S = ...;
|
||||
if (isa<Circle>(S)) {
|
||||
/* do something ... */
|
||||
}
|
||||
|
||||
The code of ``isa<>`` will eventually boil down---after template
|
||||
instantiation and some other machinery---to a check roughly like
|
||||
``Circle::classof(S)``. For more information, see
|
||||
:ref:`classof-contract`.
|
||||
|
||||
Although for this small example setting up LLVM-style RTTI seems like a lot
|
||||
of "boilerplate", if your classes are doing anything interesting then this
|
||||
@ -247,7 +256,6 @@ Then in ``Square``, we would need to modify the ``classof`` like so:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
static bool classof(const Square *) { return true; }
|
||||
- static bool classof(const Shape *S) {
|
||||
- return S->getKind() == SquareKind;
|
||||
- }
|
||||
@ -273,6 +281,16 @@ ordering right::
|
||||
| OtherSpecialSquare
|
||||
| Circle
|
||||
|
||||
.. _classof-contract:
|
||||
|
||||
The Contract of ``classof``
|
||||
---------------------------
|
||||
|
||||
To be more precise, let ``classof`` be inside a class ``C``. Then the
|
||||
contract for ``classof`` is "return ``true`` if the dynamic type of the
|
||||
argument is-a ``C``". As long as your implementation fulfills this
|
||||
contract, you can tweak and optimize it as much as you want.
|
||||
|
||||
.. TODO::
|
||||
|
||||
Touch on some of the more advanced features, like ``isa_impl`` and
|
||||
|
Loading…
Reference in New Issue
Block a user