Archived

This topic is now archived and is closed to further replies.

Shannon Barber

Final can be implemented in C++!

Recommended Posts

Shannon Barber    1681
Example:
      
#define FINAL virtual private Loki::EmptyClass; 

class KeepenDerDamdinFuggerMuttensOotten : FINAL
   {
   };
    
A compliant C++ compiler will complain about an inaccessable ctor and/dtor of the base class if you attempt to derive from KeepenDerDamdinFuggerMuttensOotten. (Need I say that MSVC incorrectly compiles it... yes even VS.Net) [edit: fix the code block, and changed the name from FINALLY to Final] [edited by - Magmai Kai Holmlor on June 8, 2002 12:57:59 PM]

Share this post


Link to post
Share on other sites
Dak Lozar    122
Hi all, way back in the day when I was learning Java I learned what finally was...

I think what Magmai is trying to do here is prevent programmers from deriving from his base class KeepenDerDamdinFuggerMuttensOotten (cool name )

Java has this ability and C++ does not...

Dave "Dak Lozar" Loeser †

Share this post


Link to post
Share on other sites
abdulla    164
I think a midly more intuitive solution would be to use a garbage collector (like Hans Boehm''s) that implements finalization, so you just register a function with the garbage collector for that object on creation, when it dies it will call it, just like Java, the notation maybe less natural, but I''m sure with a bit of fiddling you could easily make it look like Java''s notation.

Share this post


Link to post
Share on other sites
Brobanx    136
I believe you''re confusing the java keyword FINAL and FINALLY. FINALLY deals with exception handling, and FINAL means a class or function that can''t be overriden (and it is also a limited form of C++''s CONST keyword).

Share this post


Link to post
Share on other sites
Dactylos    122
quote:
Original post by abdulla
I think a midly more intuitive solution would be to use a garbage collector (like Hans Boehm''s) that implements finalization, so you just register a function with the garbage collector for that object on creation, when it dies it will call it, just like Java, the notation maybe less natural, but I''m sure with a bit of fiddling you could easily make it look like Java''s notation.

That''s not what he meant. C++ already has destructors for that purpose (minus the garbage collection of course). He is talking about declaring a class that can not be derived from (working similarly to Java''s ''final'' keyword on class declarations).

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:

A compliant C++ compiler will complain about an inaccessable ctor and/dtor of the base class if you attempt to derive from KeepenDerDamdinFuggerMuttensOotten.



C++ is a useful and flexible language, but why do we always have to resort to hacks to make it do the tricks we require? Commonly used constructs should be language features, not messy #define''s.

Share this post


Link to post
Share on other sites
Oluseyi    2112
quote:
Original post by Anonymous Poster
C++ is a useful and flexible language, but why do we always have to resort to hacks to make it do the tricks we require?

Our requirements grow and change? Go figure...

For the record, I don''t get the point. finally, AFAIK, has to do with exceptions (I believe MSVC has a non-standard __finally along with __try and __catch) while final (Java) has to do with restricting inheritance. The two seem to be mixed up here.

Share this post


Link to post
Share on other sites
felonius    122
quote:
Original post by Oluseyi
For the record, I don''t get the point. finally, AFAIK, has to do with exceptions (I believe MSVC has a non-standard __finally along with __try and __catch) while final (Java) has to do with restricting inheritance. The two seem to be mixed up here.


My thoughts exactly. So the #define above should be called FINAL, not FINALLY; at least to stay remotely consistant with Java.

final (on classes): prevent people from deriving from the class.
finally: A block that is always executed on the way out of a exception block.
finalize(): This is a so-called finalizer and in garbage collected systems these are executed for an object after all references to it is dead but before it is deallocated - if that ever happens.

Don''t confuse the above terms.

That said, I am still having trouble seeing exactly why that define should achieve the effect of final - maybe somebody here can explain it...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
in java final is also used to mean a const variable, or a non virtual function.

Anyway why would nuetering a class be desirable? I''d like to know the motivation.

Share this post


Link to post
Share on other sites
Arild Fines    968
quote:
Original post by granat
Why not keep the language simple ?

C++? _WAY_ too late for that now.

Anyway - final, as well as serving to document the intended usage of your class, allows the compiler to optimize away some virtual calls.

Share this post


Link to post
Share on other sites
Cedric    158
Isn''t it cleaner to use the named constructor idiom? Like

class A{
private:
A(int value){}
public:
static A constructor(int value){return A(value);}
};
A a = A::constructor(5);

It has its limitations... But at least, it''s not an ugly #define macro.

Besides, why would you want to make a class final anyway? Make all of your data and functions private and put a comment //Final class. I haven''t read many good arguments in favor of a final class.

And frankly, I don''t understand how the OP manages to make a class FINAL either. If it''s possible to do it with a macro, surely, you can just write the example without the macro. That would help a lot with the understanding.

Cédric

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by Arild Fines
...allows the compiler to optimize away some virtual calls.



don''t make those functions virtual then. When you override a function that is virtual in the base class you don''t have to make it virtual in the derived.

Share this post


Link to post
Share on other sites
Cedric    158
The code is a lot clearer now . But I still don't understand why the compiler should complain about an inacessible constructor. If your class is Final, then it should be a complete entity that takes care of its own problems. If I inherit from it, why would the constructor be inaccessible?

Cédric

[edited by - cedricl on June 8, 2002 1:17:58 PM]

Share this post


Link to post
Share on other sites
Shannon Barber    1681
quote:
Original post by Anonymous Poster
C++ is a useful and flexible language, but why do we always have to resort to hacks to make it do the tricks we require? Commonly used constructs should be language features, not messy #define''s.

I have to slightly disagree - commonly used constructs should not neccessarily be language features. The language should allow you to fabricate the features you want or require.
For example, a string class should *not* be built into the language. Operator overloading (and conversions) should be, which allow one to create a string class that functions in a native manor. Some needs to be built-in though. I think a macro keyword would be useful; that has similar behavior to #define''s, but obeys scope & namespace restrictions.

I thought of a way to implement final with a template as well, but the macro is eaier to use.

  
namespace {
struct Class_Has_Been_Finalized
{};
}
template<class Finalize>
struct Final : virtual private Class_Has_Been_Finalized
{
friend Finalize;
};

class KeepenDerDamdinFuggerMuttensOotten : Final<KeepenDerDamdinFuggerMuttensOotten>
{
};

And now the error would read something like, ''unable to access dtor in inaccessible base Class_Has_Been_Finalized''

quote:

Isn''t it cleaner to use the named constructor idiom?


Um, I''d say no. By reading it, it''s not clear that you don''t want someone to derive from it. It looks like some sort of factory method (or perhaps a singleton), neither of which indicate ''final''.

Making the dtor private prevents stack instances, and making the ctor private precludes the use of the STL or other concepts requring value semantics. I believe the macro has the desired effect, and only the desired effect, and prevents one from forgetting to inherit from Final as both virtual & private. I wouldn''t call that a hack. (It was hard to read because it all got bunched up on one line)

I''ve never wanted to use final, but I thought it was interesting that C++ already supports the concept.

...
quote:

...don''t make those functions virtual then. When you override a function that is virtual in the base class you don''t have to make it virtual in the derived.


Once virtual *always* virtual. Not declaring it virtual in a derived class doesn''t get rid of the virtuosity.

Share this post


Link to post
Share on other sites
Arild Fines    968
quote:
Original post by Magmai Kai Holmlor

I have to slightly disagree - commonly used constructs should not neccessarily be language features. The language should allow you to fabricate the features you want or require.


I totally disagree. If it is commonly used, it should be built into the language proper. Then there would be _one_ idiom taught to all new programmers, instead of 10 different workarounds that all are mutually incompatible. The idiom would be instantly recognizable to all programmers reading the code, instead of relying on them having read the same books as you.
Unbridled flexibility in language design is _NOT_ a good thing. If there is a good way to do something, then the language should not provide an alternative way to do the same thing. This makes code both easier to write and easier to read.




Share this post


Link to post
Share on other sites
Shannon Barber    1681
The downside to a more restrictive language, is that it''s harder to experiement with or research new techniques. It''s far more likely to require a change to the language to do something new. So I guess I prefer hacks, over impossible to implement.

quote:

But I still don''t understand why the compiler should complain about an inacessible constructor.


virtual private

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:

C++ is a useful and flexible language, but why do we always have to resort to hacks to make it do the tricks we require? Commonly used constructs should be language features, not messy #define''s.


quote:

The downside to a more restrictive language, is that it''s harder to experiement with or research new techniques. It''s far more likely to require a change to the language to do something new. So I guess I prefer hacks, over impossible to implement.



Making commonly used constructs language features does not imply a more restricted language.

Share this post


Link to post
Share on other sites
amag    152
quote:

Making commonly used constructs language features does not imply a more restricted language.


That''s exactly what it does. Go look at Ada for instance where you have threads built in as keywords (task). Ada is extremly restrictive. How can you extend the concept of a thread if it''s built in the language?
C++ is designed to be flexible, go read Bjarne Stroustrup''s column at http://www.cuj.com/current/feature.htm?topic=current if you feel like adding more to the language...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:

That''s exactly what it does. Go look at Ada for instance where you have threads built in as keywords (task). Ada is extremly restrictive. How can you extend the concept of a thread if it''s built in the language?
C++ is designed to be flexible, go read Bjarne Stroustrup''s column at http://www.cuj.com/current/feature.htm?topic=current if you feel like adding more to the language...



Adding language features doesn''t mean removing primitive constructs. You''re jumping to conclusions.

Share this post


Link to post
Share on other sites
amag    152
quote:

Adding language features doesn''t mean removing primitive constructs. You''re jumping to conclusions.


Ok, I''m jumping to conclusions, but by adding constructs to the language that are not essential (that is they can be created within the language itself) will get you to PL/1. PL/1 was designed to be *the one* language. It was huge. It had support for everything. Do you hear about anyone using PL/1 today? Didn''t think so.

So a quote from Bjarne Stroustrup:
quote:

C++ has a clearly stated philosophy of language: the emphasis in the selection of new facilities is on mechanisms for defining and using new types safely and efficiently. Basic facilities for computation were, as much as possible, inherited from Classic C and later from C89. C++ will go a long way to avoid introducing a new fundamental type. The prevailing view is that if you need one type then many programmers will need similar types. Consequently, providing mechanisms for expressing such types in the language will serve many more programmers than providing the one type as a built-in. In other words, the emphasis is on facilities for organizing code and building libraries (often referred to as “abstraction mechanisms”).

Share this post


Link to post
Share on other sites