i want to end a virtual function chain at a particular class in a hierarchy. is there a way in std c++ to do this?
Printable View
i want to end a virtual function chain at a particular class in a hierarchy. is there a way in std c++ to do this?
I can't think of any way of doing this in C++.
Try explicitly recasting this in the call to the method you want.
I think the question is more about how to prevent subclasses from overriding a virtual method. This is not directly possible in C++.
If you insist on doing it, you can wrap the class you want to "seal" in another class which just passes all method calls through directly -- the virtual method you want to "seal" will not be virtual in this wrapper so it can't be overridden. Unfortunately this breaks the inheritance hierarchy, but you're breaking it anyway by trying to seal off a virtual function
Which begs the question of what is the point of preventing a subclass from overriding a method? If you don't want to override it, just don't implement it in the subclass, or make it protected. There is no such thing as security in the source code, you cant prevent another user from overriding the function any more than you can prevent them from accessing protected or private objects by simply changing the header to make everything public. These features are there to prevent accidentally accessing them incorrectly, not to prevent manipulating the code.
I don't know about sealed, but java's final keyword can be used to make a method non virtual. This in turn allows inlining. I suspect sealed is the same.
If you want a virtual method to be inlinable, I suppose you can make the virtual function that overrides it's base call call a non-virtual inline method, and prefer the use of the non-virtual method when accessing the object through the derived class.
EDIT:A curious thing is that a quick test shows virtual and inline not to be mutually exclusive. It must be hard for a compiler to prove the method can be implemented inline in such a case.
I think the compiler will take the low hanging fruit. For instance, it would probably inline in this case:
And possibly this case:Code:MyClass foo;
foo.InlineFunction();
But not in the general case, obviously.Code:MyClass *foo = new MyClass();
// Nothing in between that could change the type of *foo
foo->InlineFunction();
inline is an optional keyword, there is no guarantee that the function will be inlined even if you use it, the compiler is free to ignore it. Also, a virtual function can be inlined even without the inline keyword, AFAIK the only way to explicitly stop the compiler inlining is to use #pragma NOINLINE and then only if the compiler supports it.
The primary function of inline, in the view of the compiler, is a question of linkage: if the linker sees multiple implementations of an inline function, it has to merge them, while for normal functions it will complain. So yes, a function may be virtual and inline.
C++0x's attribute system will support the 'final' attribute.
You can prevent a typical compiler from inlining a method by calling it in a different transaction unit than it is defined. Compilers compile one source at a time and don't look at what's in other transaction units untill linking. Since it is common practice for methods of a class to declare in their own source file, this effectively prevents non inline public and protected methods from being inlined if they are not declared as inline functions.
Hypothetically, yes a compiler could be made to inline at the linking stage, but especially because of the existence of the inline keyword and the features it provides, this is not done.
VC++, Intel C++, LLVM-based compilers, most recently even GCC all do that. It's called LTO (link time optimization) or LTCG (link time code generation).Quote:
Hypothetically, yes a compiler could be made to inline at the linking stage, but especially because of the existence of the inline keyword and the features it provides, this is not done.
That must be C#, specific, I've never heard of transaction units in C++.
This is implementation specific, there are parallel compilers that compile multiple source files simultaneously and there are several commercial compilers that inline at link time. Visual Studio for one.Quote:
Compilers compile one source at a time and don't look at what's in other transaction units untill linking. Since it is common practice for methods of a class to declare in their own source file, this effectively prevents non inline public and protected methods from being inlined if they are not declared as inline functions.
Which implies that this is no longer the case.Quote:
Originally Posted by MSDN
Which confirms that this is the case.Quote:
Originally Posted by MSDN
King Mir probably meant translation unit.Quote:
Originally Posted by abachler
I'm proven wrong then.
Yeah, I meant translation unit.
Inline is a slippery slope that I avoid and this thread is proof why. There are millions of answers and possiblities as to what each compiler does and does not do for inline. B/c of this I avoid using it. It's almost harder to figure out when the compiler will or will not inline than it is to take the hit for the function call and make sure the function is optimized.
AFAIK there is no equivalent to sealed in C++. I personally find it useless in C# b/c as abachler said if you do not want to override then don't. If you derive from the interface, however, you should be forced to implement all of it's pure virtual functions. I can't think of a reason in the world why you would need to prevent other programmers from implementing a base class pure virtual or virtual function. If a function is declared as pure virtual then you are essentially saying you must provide an implementation and if you declare it as virtual you are saying you can provide an alternate implementation. If you don't want anyone providing a different impl for the function then don't declare it in a manner that clearly is intended for that very purpose.
There are some (albiet rare) cases where you have a derived class which overrides some functions, but you don't want any class to derive from your class and override some of these same functions. In this a final/sealed C++ keyword could be useful. For the most part, you can accomplish the same thing by adding a comment that says, "DO NOT OVERRIDE THIS FUNCTION" :)
In C++ you can declare a base class function as non-virtual as a way of saying, "don't override this". In Java and C#, all functions are virtual, so declaring a function as final/sealed is the only way to accomplish the same thing. This is the main reason for the existence of these keywords -- it has nothing to do with function inlining.
I don't think anyone was connecting the two. There are two topics running throughout this thread.Quote:
it has nothing to do with function inlining.
I would call that case a case of bad design since the same could be accomplished with a much better design.Quote:
There are some (albiet rare) cases where you have a derived class which overrides some functions, but you don't want any class to derive from your class and override some of these same functions. In this a final/sealed C++ keyword could be useful. For the most part, you can accomplish the same thing by adding a comment that says, "DO NOT OVERRIDE THIS FUNCTION"
Post #7 connected the two.
It depends. It's easy to say "that's bad design" in theory. On the other hand, there may be some valid case where your derived class needs to call a virtual function from the constructor. Now you don't want any classes that are deriving from you to override that same virtual function due to the odd behavior that would produce. In this case, a "final" keyword would be nice to have.
Yes it does. A virtual function cannot in the general case be inlined. I don't know C# but in java, all references are potencially references to a derived class, and therefore every call to a non final function requires vtable lookup. This prevents inlining. By declaring a method final vtable look up is not neccessairy. the function is effectively non virtual when called with a reference to the class in which that function is declared final. This allows inlining.
This is the only real use of the final functions. In other cases using final just unduly limits the programmer. If you are designing a module/package, and the function in question is to be derived within the module, then the final keyword is not useful, because it is plain to see that your more derived classes do not derive the base class. If you are instead designing a class that is meant to be derived from across API boundaries, then you are unduly limiting the user of your class. What benefit does the user receive of being unable to make a debug wrapper around calls to that function?
Only functions that you think are candidates for inlining should be declared final in Java.
You may have a point with calls from a constructor. I'm not totally convinced though. Can you maybe give a code example?
This is a very contrived example (not compiled, so please excuse any typos):
Depending on the work being done in foo(), this can have some unintended consequences since creating a new derived2 object will call derived1's foo() even though derived2 has overridden the function.Code:#include <iostream>
class base
{
public:
virtual void foo(void) {
std::cout << "in base foo()\n";
}
};
class derived1 : public base
{
public:
derived1(void) {
foo();
}
// would be nice to declare this as "final"
void foo(void) {
std::cout << "in derived1 foo()\n";
}
};
class derived2 : public derived1
{
public:
void foo(void) {
std::cout << "in derived2 foo()\n";
}
};
int main()
{
base* b = new derived2();
b->foo();
delete b;
}
As a safety rule, you simply should never call virtual functions, or functions that transitively call virtual functions, from the constructor. I can't imagine a design where doing so would be the right thing.
I don't like it. It hinders design, like some standard library classes which insists on using private instead of protected.
And it will probably be abused too. It's a shame that we are getting a final keyword in C++.
As for the whole inlining topic... what's the deal with avoiding it? Let the compiler do its job. Whether it inlines them or not is up to the compiler and not to us. Why should we care? If it does it, then great. If not, no big loss. Let's just not depend on the compiler inlining it for us.
@bithub
I suppose there are cases where that could cause problems.
Would that not imply a broken optimization? Sure, those things happen, but we don't turn off optimizations because they "might" break something, do we?
@Elysia
The issue is that it is hard for the compiler to inline virtual functions, because whenever a method is accessed though a class pointer or reference it has to do vtable lookup. Only if the compiler somehow knows that a reference or pointer is not to a child of the object type pointed to can vtable lookup be inlined. A final-like property would eliminate this problem, and inlineing is made possible as a result. This is how the final key word is useful in Java. Even without inlining, it would be eliminating a level of indirection (in C++), but inining is the real gain.
I seem to be repeating this for the third time now. Maybe I should let somebody else explain it.
I saw that, but I don't like it. It limits design options and can be easily abused.
There's a lot in C++ that can be abused. C++ is meant to be a powerful and fast, and this aids in that goal. Being hard to abuse is not a design goal of C++.
Final is not used much for functions in Java. Why would it become a problem in C++?
I'm no experienced Java dev, so I cannot comment on that.
I did see some silly code that did restrict inheritance with the use of final, though. Of course, this was just some homework...
Well, I'm still no fan of final, and I'd probably never use it, but whatever is, is, I suppose. No way to change that.
It's easy to say it's bad design because it is. C/C++ are not intended to be 'programmer safe'. They are intended to allow real programmers, as opposed to script kiddies, to use the code in the most flexible manner possible. Adding a keyword just to prevent some particularly bad design choice from crashing the system merely leads to portability problems. This isn't a lack of a feature in C++, its a lack of a feature in C# and that feature is called flexibility. However contrived an example you can present, I am pretty sure there exist more instances of code where 'final' is used as a variable name than exist real instances where final will prevent bad code.
There has never been, nor will there ever be, a programming language in which it is the least bit difficult to write bad code.
In fact I can foresee a case where it would CAUSE bad code. i.e. if I have a derived class that must implement new behavior for a finalized method, what will happen, will C# spit an error requiring me to remove the final keyword, thereby breaking all the other derived classes, or will it silently fail to implement my over-ridden method and lead to lost man hours tracking down a bad design choice?
No, it is better that the final keyword not even exist in C++. That way the programmer must explicitly decide whether to override a method or not. This would of course all come out in the RFC discussions if C# wasn't an entirely contrived language that brings nothing to the table. MS just felt in its hubris that 'they know best' and is trying to force this piece of crap language on people.
A constructor must be public? Since when?
@abachler
Where bithub's example seems most likely to fix a problem as I see it is if derived1 and base are part of a librairy, and derived2 is written by someone using that librairy. The documentation of derived1 may fail to mention that foo is called by a constructor, or it change what it does in different versions. If is possible to document that derived1 is not meant to be derived from, but there may not be a problem with deriving from derived1 excepting this problem. So the best solution is to add a final like feature.
As for adding keywords, CornedBee said that final would be an attribute, not a keyword so the problem does not exist as you describe. Attributes are surrounded by double brackets which do not occur in current C++.
In C++ it would have to be implemented as a keyword.
And again, C++ is not intended to prevent a programmer from shooting themselves in the foot, it is intended to allow maximum flexibility. There is no point in restricting the use of derived methods if the programmer wishes to do so. If you need to restrict inheritance then simply make the method private or protected, or better yet Don't declare it virtual in the first place and it can no longer be inherited. You can do this in C# as well, so adding final was pointless. Declaring a method virtual and then finalizing it is basically just removing everything that virtual did in the first place. So what is next, keywords to let you declare a variable as type double, then a keyword to undeclare it so that you can redeclare it as int? I think final is a solution in search of a problem that doesn't exist, and for which if it did exist, there are already better solutions in place.
throws an error.Code:NotInheritable* pTest = new NotInheritable();
Create is not a constructor, it is an method function, there is a big difference. I also suspect that you are either directly calling the member function without creating an instance of the class, or you are leaking memory as there is no way to delete the instance without a pointer and no way to guarantee which instance of the class you are accessing. After testing, it appears that you are actually accessing a new instance each time, so there is no way to make the class more complex, e.g. with member variables, as they are destroyed after a single function call. So basically this kludge is nothing but a way to group a set of functions together, something that could more easily be done by simply using a separate namespace, since you are already creating a namespace to begin with.Quote:
Originally Posted by Visual Studio
Code:#include <iostream>
class NotInheritable {
public:
static NotInheritable Create() { return NotInheritable(); }
void foo() { std::cout << "foo\n" << this << "\n" << this->Test << "\n"; this->Test++; }
int Test;
private:
NotInheritable() { this->Test = 0; }
};
int main(){
//NotInheritable* pTest = new NotInheritable();
NotInheritable::Create().foo();
NotInheritable::Create().foo();
return 0;
}
Not if it's as CornedBee describes. C++0x attributes are described in Wikipedia here. It doesn't mention final, but if its in C++0x it would use the same type of syntax.
Making a method protected or private has the side effect that it can no longer be called be a non derived pointer outside the class. That's not the intent of final/sealed.Quote:
And again, C++ is not intended to prevent a programmer from shooting themselves in the foot, it is intended to allow maximum flexibility. There is no point in restricting the use of derived methods if the programmer wishes to do so. If you need to restrict inheritance then simply make the method private or protected and it can no longer be inherited. You can do this in C# as well, so adding final was pointless.
C++ is intended to make it hard for programmers to accidentally shoot themselves in the foot. A final key word like feature for methods would in fact add flexibility because where as before the danger of constructor calling a virtual method would be a worry for deriving from a class that is not intended to be derived from. With that worry removed, deriving from a class that not so risky.
But this is secondary to the optimization benefits that final and sealed provide. High potential for optimization is a goal of C++.
It throws an error because you're doing it wrong...
And there is no memory leak, and I'm not calling the member function without a class instance. The object is copy constructed when it is returned.
You can just as easily modify the Create() function to return a pointer from the heap if you desire it that way (similar to the singleton design pattern).
Re: not declaring it as virtual in the first place.
That's only possible if the method in question is of the base class. In the example, derived1 calls a function that is made virtual in the base class.
Again, the two solutions are either to avoid calling the virtual function, or to declare the function as final. Sometimes the second would seem more elegant.
OMG. What is this nonsense?
It's not destroyed. It returns a new instance which can be used for whatever you want. In bithub's example, it is indeed destroyed directly, but that is the fault of the demonstrated code, not the design.
Ever heard of a factory? It usually uses a pattern like this, where the constructor is private.
It was brewbuck's code...
You didn't take my code and add a main function, I didn't post that piece of crap class, you did. I ran the code to verify that it fails and immediately destroys the class, making it useless for anything but a collection of functions.
As the modifications I made show, it destroys the class immediately after the method exits. It does NOT return a new instance at all, there is no way of accessing the class because it is ........ing destroyed as soon as the method returns, so even if you added code to return this, it would point to an invalid location that will crash if you try to access the class since it was ........ing destroyed.Quote:
Originally Posted by Elysia
The code works. I don't know what example you are using but try this:
A key here is that though the default constructor is private, the copy constructor is not.Code:#include <iostream>
class NotInheritable
{
public:
static NotInheritable Create() { return NotInheritable(); }
void foo() { std::cout << "foo\n"; }
private:
NotInheritable() {}
};
int main()
{
NotInheritable var = NotInheritable::Create();
var.foo();
}
And no, you can't add code to return this, because Create is a static method.
Which makes it useless as there is no way to access the class.Quote:
And no, you can't add code to return this, because Create is a static method.
The code
at least works at producing usable classes, the code originally posted did not. Although I personally woudl never use this method as it seems to be much more work than simply using new. Particularly if you are creating the class in one thread and using it in another. This method would destroy the class when var1/var2 goes out of scope.Code:#include <iostream>
class NotInheritable {
public:
static NotInheritable Create() { return NotInheritable(); }
void foo() { std::cout << this << "\n"; }
private:
NotInheritable() {}
};
int main(){
NotInheritable var1 = NotInheritable::Create();
var1.foo();
NotInheritable var2 = NotInheritable::Create();
var2.foo();
}
My mistake, brewbuck posted it, you just quoted it.
That's where you're wrong. The class is copied. It is the equivalent to doing:
The object is copied before it is destroyed. That is why it is still valid for the caller.Code:std::string get_string() { return std::string("hello"); }
void foo() {
std::cout << "size is " << get_string().size() << std::endl;
}
They're right, Abachler. Consider:
The temporary isn't destroyed until the final print statement executes...Code:
#include <iostream>
#include <string>
using namespace std;
class example
{
public:
example const& print( string const& text ) const
{
cout << reinterpret_cast< int const* >( this ) << " : " << text << endl;
return *this;
}
static example create( void )
{
return example( );
}
example( example const& )
{
print( "example( example const& )" );
}
~example( void )
{
print( "~example( void )" );
}
private:
example( void )
{
print( "example( void )" );
}
};
int main( void )
{
example::create( ).print( "1" ).print( "2" ).print( "3" )
.print( "4" ).print( "5" ).print( "6" ).print( "7" )
.print( "8" ).print( "9" ).print( "10" );
return 0;
}
Only because the methods are recursively calling the class, once the call chain ends and the variable goes out of scope, the class is automatically destroyed, which may be fine for int main{ Foo() } examples, but it just will not do when creating the object and passing it to another thread, e.g. in a server application using separate listen() and processing threads.. While you can create a pointer to the object and pass that, you still have the scope issue, if the creating thread terminates, the object goes out of scope, causing the recipient thread to try to access an object that no longer exists. Using new, and creating it properly completely avoids this issue altogether. The object is never destroyed until your application explicitly delete's it.
It's poor design, regardless of whether or not it compiles and runs.
True, you couldn't pass a reference to the temporary to another thread, but the same holds for any non-global variable from an unrelated scope. No problem, you just need to pass a copy to the thread. All it really boils down to, then, is that the class has to be copy-constructible. Even so, the compiler can still choose to employ "return value optimization" (RVO), in which case the temporary is eliminated altogether. For example, when I compile and run this:
...The output is:Code:
int main( void )
{
example
copy = example::create( );
copy.print( "1" ).print( "2" ).print( "3" )
.print( "4" ).print( "5" ).print( "6" ).print( "7" )
.print( "8" ).print( "9" ).print( "10" );
return 0;
}
0x43f003 : example( void )
0x43f003 : 1
0x43f003 : 2
0x43f003 : 3
0x43f003 : 4
0x43f003 : 5
0x43f003 : 6
0x43f003 : 7
0x43f003 : 8
0x43f003 : 9
0x43f003 : 10
0x43f003 : ~example( void )
So, the code that was originally posted by Brewbuck was neither broken nor poor design - it's a perfectly sound solution to the problem, actually. Of course, personally, I'd never use it - I don't even bother with protected/private encapsulation in my own code, most of the time. The way I see it, if I don't want to have easy access to the internals, I can just mangle the member names - that way, if I really *do* need to mess with things, I can...the obfuscated identifier is reminder enough that I'm flirting with disaster!