|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
The Boost library has taught me that C++ is powerful enough (by
overloading operators and using templates) to have its syntax and semantic modified to such an extent that seemingly impossible features like lambda functions, variant variables, container initializers, etc. are very possible. So, I don't want to say too hestantly that it is impossible to simulate the finalizing of virtual methods and classes in C++. Hence, I rather turn to the experts and ask if anyone knows if it is possible to simulate them in any way? For the problem of finalizing a class, I tried the following way: template<class A> class finalized { private: finalized() {} friend class A; // ERROR: Cannot use template parameter in a friend statement. }; class CannotDerived : virtual private finalized<CannotDerived> { public: CannotDerived() {} }; But this doesn't compile for reason stated in the code. However, I can modify the above idea into something that works: class finalized_CannotDerived { private: finalized_CannotDerived() {} friend class CannotDerived; }; class CannotDerived : virtual private finalized_CannotDerived { public: CannotDerived() {} }; This works but not as elegant. Well, at least I have a way, albeit not so elegant, for finalizing a class, but I'm still out-of-wit on how to finalize a virtual method. Moreover, the more I think about it, the more I'm convinced it cannot be done. I hope someone can prove me wrong here. -- // kira |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
Kira Yamato <kirakun@earthlink.net> wrote in <2008022206570016807-kirakun@earthlinknet>: > So, I don't want to say too hestantly that it is > impossible to simulate the finalizing of virtual methods > and classes in C++. > > Hence, I rather turn to the experts and ask if anyone > knows if it is possible to simulate them in any way? This is a FAQ. <http://www.parashift.com/c++-faq-lite/> -- When all you have is a transformation engine, everything looks like a tree. |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
On 2008-02-22 07:35:34 -0500, Pavel Lepin <p.lepin@ctncorp.com> said:
> > Kira Yamato <kirakun@earthlink.net> wrote in > <2008022206570016807-kirakun@earthlinknet>: >> So, I don't want to say too hestantly that it is >> impossible to simulate the finalizing of virtual methods >> and classes in C++. >> >> Hence, I rather turn to the experts and ask if anyone >> knows if it is possible to simulate them in any way? > > This is a FAQ. > > <http://www.parashift.com/c++-faq-lite/> Yes. Thanks. But the FAQ does not say that finalizing method is impossible. If in fact it did, then the answer is found. Instead, it just proposes a "solution." So let me try asking differently, has anyone gotten further with a better solution than merely stating a comment? -- // kira |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
* Kira Yamato:
> On 2008-02-22 07:35:34 -0500, Pavel Lepin <p.lepin@ctncorp.com> said: > >> >> Kira Yamato <kirakun@earthlink.net> wrote in >> <2008022206570016807-kirakun@earthlinknet>: >>> So, I don't want to say too hestantly that it is >>> impossible to simulate the finalizing of virtual methods >>> and classes in C++. >>> >>> Hence, I rather turn to the experts and ask if anyone >>> knows if it is possible to simulate them in any way? >> >> This is a FAQ. >> >> <http://www.parashift.com/c++-faq-lite/> > > Yes. Thanks. But the FAQ does not say that finalizing method is > impossible. If in fact it did, then the answer is found. Instead, it > just proposes a "solution." > > So let me try asking differently, has anyone gotten further with a > better solution than merely stating a comment? There should be no reason to finalize a member function in C++. But if you absolutely must it's not that difficult. class Base { friend class Derived; private: struct OverrideTag {}; public: virtual void foo( OverrideTag = OverrideTag() ) = 0; }; class Derived: public Base { public: virtual void foo( OverrideTag = OverrideTag() ) {} }; class FurtherDerived: public Derived { public: // Nix njet. // virtual void foo( OverrideTag = OverrideTag() ) {} }; int main() { Derived o; o.foo(); } However, chances are that if you do something like this then you're thinking in Java, not in C++, using ideas that don't make sense in C++. Cheers, & hth., - Alf -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On 2008-02-22 08:05:28 -0500, "Alf P. Steinbach" <alfps@start.no> said:
> * Kira Yamato: >> On 2008-02-22 07:35:34 -0500, Pavel Lepin <p.lepin@ctncorp.com> said: >> >>> >>> Kira Yamato <kirakun@earthlink.net> wrote in >>> <2008022206570016807-kirakun@earthlinknet>: >>>> So, I don't want to say too hestantly that it is >>>> impossible to simulate the finalizing of virtual methods >>>> and classes in C++. >>>> >>>> Hence, I rather turn to the experts and ask if anyone >>>> knows if it is possible to simulate them in any way? >>> >>> This is a FAQ. >>> >>> <http://www.parashift.com/c++-faq-lite/> >> >> Yes. Thanks. But the FAQ does not say that finalizing method is >> impossible. If in fact it did, then the answer is found. Instead, it >> just proposes a "solution." >> >> So let me try asking differently, has anyone gotten further with a >> better solution than merely stating a comment? > > There should be no reason to finalize a member function in C++. > > But if you absolutely must it's not that difficult. > > class Base > { > friend class Derived; > private: > struct OverrideTag {}; > public: > virtual void foo( OverrideTag = OverrideTag() ) = 0; > }; > > class Derived: public Base > { > public: > virtual void foo( OverrideTag = OverrideTag() ) {} > }; > > class FurtherDerived: public Derived > { > public: > // Nix njet. > // virtual void foo( OverrideTag = OverrideTag() ) {} > }; Neat. So, it uses a similar trick as the final class method. You should email the owner of the C++ FAQ and propose this as another possible solution. > > [...] > However, chances are that if you do something like this then you're > thinking in Java, not in C++, using ideas that don't make sense in C++. I'm not disagreeing with you here, but I like to hear the reason why you feel that this is not necessary (or maybe even wrong) in C++ to finalize methods. -- // kira |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
Alf P. Steinbach wrote:
> * Kira Yamato: >> So let me try asking differently, has anyone gotten further with a >> better solution than merely stating a comment? > > There should be no reason to finalize a member function in C++. [...] > However, chances are that if you do something like this then you're > thinking in Java, not in C++, using ideas that don't make sense in C++. I don't agree. There are performance issues. Example: ----- #include <stdio.h> struct A { virtual void foo() { puts("A::foo()"); } }; struct B : public A { /* final */ void foo() { puts("B::foo()"); } }; int main() { B* x = new B; x->foo(); // <--- delete x; return 0; } ----- The line marked with "<---" could never expand the function B::foo() inline unless the compiler knows that it is final. On the other side a compiler may at least call any virtual member function of a class C with a pointer of type C* as 'this' without a vtable lookup as long as it knows that the function cannot be overwritten. (Of course, in that particular case a global optimizer may find that x always points to B. But that is another topic.) Marcel |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
* Marcel Müller:
> Alf P. Steinbach wrote: >> * Kira Yamato: >>> So let me try asking differently, has anyone gotten further with a >>> better solution than merely stating a comment? >> >> There should be no reason to finalize a member function in C++. > [...] >> However, chances are that if you do something like this then you're >> thinking in Java, not in C++, using ideas that don't make sense in C++. > > > I don't agree. There are performance issues. > > > Example: > > ----- > #include <stdio.h> > > struct A > { virtual void foo() > { puts("A::foo()"); > } > }; > > struct B : public A > { /* final */ void foo() > { puts("B::foo()"); > } > }; > > int main() > { B* x = new B; > x->foo(); // <--- > delete x; > return 0; > } > ----- > > > The line marked with "<---" could never expand the function B::foo() > inline unless the compiler knows that it is final. > On the other side a compiler may at least call any virtual member > function of a class C with a pointer of type C* as 'this' without a > vtable lookup as long as it knows that the function cannot be overwritten. > > (Of course, in that particular case a global optimizer may find that x > always points to B. But that is another topic.) That's no reason. First it's premature optimization until you've measured and found that the virtual call is a bottleneck. Which is highly unlikely on modern computers and with modern compilers. Check out the committee's efficiency paper. Second, if against all expectation that call should turn out to be a bottleneck, one simple cure is to use a non-virtual member function: that's what they're for, no virtual call (that's one difference between C++ and Java ;-) ). Cheers, & hth., - Alf -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
Alf P. Steinbach wrote:
> * Marcel Müller: >> The line marked with "<---" could never expand the function B::foo() >> inline unless the compiler knows that it is final. >> On the other side a compiler may at least call any virtual member >> function of a class C with a pointer of type C* as 'this' without a >> vtable lookup as long as it knows that the function cannot be >> overwritten. > > That's no reason. > > First it's premature optimization until you've measured and found that > the virtual call is a bottleneck. Which is highly unlikely on modern > computers and with modern compilers. Well, with arguments like this applied to all levels of software development from the compiler to the application design, you can ensure that we need more and more computing power even for trivial tasks. (That is in fact what's happening. But the compilers only have a very small part in that.) > Check out the committee's > efficiency paper. The virtual call is no problem. But the missing inlining may be a significant overhead in some cases. In conjunction with generic programming trivial functions are more often used. > Second, if against all expectation that call should turn out to be a > bottleneck, one simple cure is to use a non-virtual member function: Of course, that's a work-around without runtime overhead. However, it's unclear to provide two interfaces. One for base class users and another for the others. But you are right, we should not overstate that topic. Marcel |
|
|
|
#9 |
|
Messages: n/a
Hébergeur: |
Marcel Müller <news.5.maazl@spamgourmet.org> wrote in news:47bf0286$0
$2292$9b4e6d93@newsspool4.arcor-online.net: > > >> Second, if against all expectation that call should turn out to be a >> bottleneck, one simple cure is to use a non-virtual member function: > > Of course, that's a work-around without runtime overhead. > > However, it's unclear to provide two interfaces. One for base class > users and another for the others. Well if you know what class you are in, you can always invoke the function like this: class A { public: virtual int foo() = 0; } class B : public A { public int foo() { return 5; } }; B* p = new B; p->B::foo(); You will find that the compiler has created a direct call to foo instead of going through the virtual. > > But you are right, we should not overstate that topic. > > > Marcel Couldn't agree more. ![]() joe |
|
|
|
#10 |
|
Messages: n/a
Hébergeur: |
Alf P. Steinbach wrote:
> * Kira Yamato: >> On 2008-02-22 07:35:34 -0500, Pavel Lepin <p.lepin@ctncorp.com> said: >> >>> >>> Kira Yamato <kirakun@earthlink.net> wrote in >>> <2008022206570016807-kirakun@earthlinknet>: >>>> So, I don't want to say too hestantly that it is >>>> impossible to simulate the finalizing of virtual methods >>>> and classes in C++. >>>> >>>> Hence, I rather turn to the experts and ask if anyone >>>> knows if it is possible to simulate them in any way? >>> >>> This is a FAQ. >>> >>> <http://www.parashift.com/c++-faq-lite/> >> >> Yes. Thanks. But the FAQ does not say that finalizing method is >> impossible. If in fact it did, then the answer is found. Instead, it >> just proposes a "solution." >> >> So let me try asking differently, has anyone gotten further with a >> better solution than merely stating a comment? > > There should be no reason to finalize a member function in C++. > > But if you absolutely must it's not that difficult. > > class Base > { > friend class Derived; > private: > struct OverrideTag {}; > public: > virtual void foo( OverrideTag = OverrideTag() ) = 0; > }; > > class Derived: public Base > { > public: > virtual void foo( OverrideTag = OverrideTag() ) {} > }; > > class FurtherDerived: public Derived > { > public: > // Nix njet. > // virtual void foo( OverrideTag = OverrideTag() ) {} > }; > > int main() > { > Derived o; > o.foo(); > } What's to stop somebody from making OverrideTag public in the derived class? [1] struct Derived: Base { using Base::OverrideTag; virtual void foo( OverrideTag = OverrideTag() ) { } }; [1] I was confused by something like this a couple months ago, and posted a question about it (here, I think). I got a few explanatory responses of the form "What do you mean you didn't think of that? Everybody knows that, and you have no right to find it confusing." I love the fact that people find everything obvious, just as soon as it has been pointed out to them. ![]() |
|
|
|
#11 |
|
Messages: n/a
Hébergeur: |
* Jeff Schwab:
> Alf P. Steinbach wrote: >> * Kira Yamato: >>> On 2008-02-22 07:35:34 -0500, Pavel Lepin <p.lepin@ctncorp.com> said: >>> >>>> >>>> Kira Yamato <kirakun@earthlink.net> wrote in >>>> <2008022206570016807-kirakun@earthlinknet>: >>>>> So, I don't want to say too hestantly that it is >>>>> impossible to simulate the finalizing of virtual methods >>>>> and classes in C++. >>>>> >>>>> Hence, I rather turn to the experts and ask if anyone >>>>> knows if it is possible to simulate them in any way? >>>> >>>> This is a FAQ. >>>> >>>> <http://www.parashift.com/c++-faq-lite/> >>> >>> Yes. Thanks. But the FAQ does not say that finalizing method is >>> impossible. If in fact it did, then the answer is found. Instead, >>> it just proposes a "solution." >>> >>> So let me try asking differently, has anyone gotten further with a >>> better solution than merely stating a comment? >> >> There should be no reason to finalize a member function in C++. >> >> But if you absolutely must it's not that difficult. >> >> class Base >> { >> friend class Derived; >> private: >> struct OverrideTag {}; >> public: >> virtual void foo( OverrideTag = OverrideTag() ) = 0; >> }; >> >> class Derived: public Base >> { >> public: >> virtual void foo( OverrideTag = OverrideTag() ) {} >> }; >> >> class FurtherDerived: public Derived >> { >> public: >> // Nix njet. >> // virtual void foo( OverrideTag = OverrideTag() ) {} >> }; >> >> int main() >> { >> Derived o; >> o.foo(); >> } > > What's to stop somebody from making OverrideTag public in the derived > class? > > struct Derived: Base { > using Base::OverrideTag; > virtual void foo( OverrideTag = OverrideTag() ) { } > }; Nothing. So Base just provides a service to Derived: "you can make this function final if you want, and that's what you get by default". The whole thing about support in Base is just because C++ doesn't have 'final', which would only appear in Derived, none of Base's business. But I gather, if someone want's it bad enough, they can add support in the base class... Or introduce an artifical base class. Cheers, - Alf -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
|
|
#12 |
|
Messages: n/a
Hébergeur: |
Marcel Müller wrote:
> Alf P. Steinbach wrote: >> * Kira Yamato: >>> So let me try asking differently, has anyone gotten further with a >>> better solution than merely stating a comment? >> >> There should be no reason to finalize a member function in C++. > [...] >> However, chances are that if you do something like this then you're >> thinking in Java, not in C++, using ideas that don't make sense in >> C++. > > > I don't agree. There are performance issues. > > > Example: > > ----- > #include <stdio.h> > > struct A > { virtual void foo() > { puts("A::foo()"); > } > }; > > struct B : public A > { /* final */ void foo() > { puts("B::foo()"); > } > }; > > int main() > { B* x = new B; > x->foo(); // <--- > delete x; > return 0; > } > ----- > > > The line marked with "<---" could never expand the function B::foo() > inline unless the compiler knows that it is final. > On the other side a compiler may at least call any virtual member > function of a class C with a pointer of type C* as 'this' without a > vtable lookup as long as it knows that the function cannot be > overwritten. > (Of course, in that particular case a global optimizer may find > that x always points to B. But that is another topic.) No, it's not really another topic! In Java you have all functions made virtual by default. Sometimes you might want to turn that off. In C++, functions are only virtual if you explicitly ask for it. There should be no need to turn if off again - just don't make them virtual in the first place. Bo Persson |
|
|
|
#13 |
|
Messages: n/a
Hébergeur: |
On Feb 22, 10:15 pm, "Bo Persson" <b...@gmb.dk> wrote:
> Marcel Müller wrote: [...] > In Java you have all functions made virtual by default. > Sometimes you might want to turn that off. > In C++, functions are only virtual if you explicitly ask for > it. There should be no need to turn if off again - just don't > make them virtual in the first place. In C++, you might, in a derived class, want to declare that a virtual function should not be overridden. Consider, for example, a case where you use a class using the template method pattern to implement an interface. In that class, you override the implementations of the (pure) virtual functions in the interface, but you do not what classes which derive from your class to override your overrides. In such case, final would be useful (although in practice, I've not found such accidental overrides to be a real problem). Conceptually, there are two orthogonal concepts: overrides, and can be overridden. That makes four combinations: doesn't override, cannot be overridden doesn't override, can be overridden overrides, cannot be overridden overrides, can be overridden In C++, you can't express the third; in Java, you can't express the first two (for anything but private---for private functions, you can't express the last three). Ideally, I'd like something like: /* no modifier */ virtual overrides final to distinguish all four cases. But as I said, in practice, it's not enough of a problem to warrent changing the language (especially given the amount of code this change would break). -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
![]() |
| Outils de la discussion | |
|
|