wnames that I've given the structs! They just get in the way.
Note: With my compiler, if I remove the
it still compiles, but the fields
hSum etc. do not exist, ie
the compiler simply ignores the whole inner structs.
enumto define constants, which can be OR'ed together to form the set of desired flags. However, you cannot use named enumerations for this because the
|(OR) operator is not defined on enums, only on ints. Of course unnamed enums have the disadvantage of having no type safety. Here is an example:
bit_enumconstruction would make this sort of situation so much easier to program, and more type-safe:
Vectoras an example, but they all use the same type for both operands of a binary operator, like this:
Matrix<int>together? I would want something like this:
operator+(T1,T2)returns. As C++ currently stands, I would have to explicitly specify the return type in a third template parameter, which, needless to say, would get ugly pretty quickly.
So I would like to propose the following:
return_typeto find out the return type of a function. It should work on built-in operators as well as user-defined ones.
MyInt, which can take a variety of operands. I can write this as a template function, which I can then specialize to define
operator+for new types:
operator+only if no others match. In C++, every time you create a subclass of
Complex<>you would have to redefine
This could be done much more elegantly if we could specify restrictions on the template parameters. Here are three possible ways in which restricted template matching could be used to solve the above problem:
Tso that a type matches
operator+(int,T)exists. Perhaps we could use the default template parameter syntax for this:
T2can be any type, except it is restricted to being a subclass of
Complex<T1>, for some other type
base_typeto represent the ficticious class from which all types are derived from, including built-in types. At first sight, the additional
base_typedoesn't seem to be putting any restriction on
Tat all, since all types are derived from
base_type. However, this would change the order of preference for the template matching algorithm, since
MyComplexwould match both
Complex<T>is the better match.
List::Iterator::Iteratorto be implicit, rather like a
thispointer. The constructor would then invisibly store
It would go something like this:
auto, meaning "non-static". Unfortunately, the current C++ standard treats nested classes as static by default, so this was necessary to maintain compatibility. It would have been more logical from a syntax point of view to have made
classmean non-static, and
static classmean what we have in the current C++ standard.
Notice that fields from the parent class, such as
be accessed directly. If it is necessary to spell out the names,
you would write
this->List::data. This direct access of parent's data
is analogous to ordinary classes, which can access global variables
directly. (Think of static storage as being one big class!!)
Here are some examples of how types could benefit from the same sort of virtual mechanism:
(n=2)is of type MyInt, not MyIntExtra, so ExtraTask() is not a method. This problem must be solved by adding an operator= to the definition of class MyIntExtra so that it returns a MyIntExtra instead of a MyInt. This is very cumbersome if you have a lot of subclasses.
But let's say we had a virtual type called
which, even in the base class, always refers to the type of the top-most
(most-derived) class. Then we could define operator= like this:
Notice that the use of
type_of_this must be severely limited
in order to maintain type-safety. A method whose return type is
type_of_this cannot return any old MyInt. It must return
a MyInt that is guaranteed to be of type
Admittedly, that example seems a little esoteric; (who uses the return
operator= anyway?!) But in many cases I think it is
more esthetically pleasing to mimic the
behavior of the standard types as closely as possible.
If there were such a thing as
virtual typedef in C++, we
could add the keyword
virtual at the indicated places,
and the return types and
parameter types of
change automatically to the correct type.
Again, in the interests of type-safety, it is necessary to note some things:
Itemrather than hiding the old one, as a regular typedef would do.
type_of_thisis exactly the same as a
virtual typedef, except that when you derive a subclass, it is "updated" automatically without you having to type anything.
MyList::NextItemcannot usually be passed any old Item* as a parameter. Only one that is guaranteed to be compatible with the Item* of the most-derived class can be passed.
The rules are complicated for determining whether type-safety is guaranteed and I make no attempt to formulate them here. But to see the subtleties involved, consider this example:
list2really is a MyList or if it is a subclass of MyList, whereas
list1definitely is a MyList because we created it right there.
Note: It is tempting to try to extend the
typedef concept even further. Rather
than defining a
struct ListItem and then creating
virtual typedef, it would appear simpler to just declare
the struct as being virtual, like this:
The problem with this is as follows: with virtual typedefs, you can only
create pointers or references, because the size of the type is unknown.
(This is because a derived class may have "updated" it.) But we will,
in all probability, want to create objects of type
That is why it is better to create a concrete type, and then make a
virtual typedef of it.
But is this a problem? You can also unvirtualize methods by explicit referencing.