Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Using nonvirtual inheritance for informal 'interfaces'?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
18 replies to this topic

#1 Waterlimon   Crossbones+   -  Reputation: 2633

Like
0Likes
Like

Posted 13 June 2013 - 11:17 AM

Is it a good idea to make interfaces like

class Foo
{
    void bar()
    {
        assert(false); //Not implemented in derieved class, go fix nao.
    }
}

class Derieved : public bar
{
    void bar()
    {
        print("yay");
    }
}

to have some idea what methods a class should have, when i need some common functionality for the classes to be used as template args?

 

One problem i see is that it wont fail at compile time if something is not implemented. Is there a way to do something like this, so that a compile time failure would result if something is missing and the base class version is called instead (which will fail at runtime due to the assert)?

 

An obvious solution is to simply comment out the ": public bar" section.

 

Or do you recommend just creating some documentation in a place well hidden somewhere with outdated information as to what methods/typedefs a class should implement to be a 'valid' value for certain templates?


o3o


Sponsor:

#2 frob   Moderators   -  Reputation: 22684

Like
2Likes
Like

Posted 13 June 2013 - 11:59 AM

Make it an abstract function in the base.

class Foo
{
   virtual bar() = 0;
}

Also note that in your example, the bar() function will hide the base function; it must be marked virtual in order for it to work the way you expected.


Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#3 Waterlimon   Crossbones+   -  Reputation: 2633

Like
0Likes
Like

Posted 13 June 2013 - 12:20 PM

I want it to hide the bases methods. This has no actual need, i just want some structure in my program.

I want a class that says that all derieving classes must implement this and this, but i dont want to use virtuals since im not intending to use the classes polymorphically.

Like i said, a solution would be to comment out the ": public Foo" part.


o3o


#4 Ravyne   GDNet+   -  Reputation: 8060

Like
0Likes
Like

Posted 13 June 2013 - 12:23 PM

Right, first be aware of the differences between inheritance of virtual and non-virtual member functions.

 

If you want a compile time error, use virtual inheritance as Frob shows. Otherwise, if you wanted a run-time assert, or some other default action, its something of a little known fact that you actually *can* give a virtual function an implementation. Derived classes must still implement a version of that function, but they can call specifically to the base class' "default" implementation. This is probably more useful when there is a reasonable default for the method though, rather than just asserting, etc.



#5 Waterlimon   Crossbones+   -  Reputation: 2633

Like
0Likes
Like

Posted 13 June 2013 - 12:33 PM

The reason i dont want to use virtuals is because i dont need polymorphism and it would add extra overhead.

 

But, if i have a pure abstract base class, will there actually be any overhead (will there be a vtable?)

 

Can i use a pure abstract base class as a compile time enforcement to force the derieving classes to implement certain methods (although i cannot force the classes to derieve from the base class in my template functions)?


o3o


#6 SiCrane   Moderators   -  Reputation: 9662

Like
1Likes
Like

Posted 13 June 2013 - 12:44 PM

I don't really see the point. If you try calling a member function on a class that doesn't support it you'll get a compiler error even without any tricky base class usage.



#7 Waterlimon   Crossbones+   -  Reputation: 2633

Like
0Likes
Like

Posted 13 June 2013 - 12:49 PM

I don't really see the point. If you try calling a member function on a class that doesn't support it you'll get a compiler error even without any tricky base class usage.

 

I know.

 

But i would like a way to document the code in a better way than a random comment somewhere saying what the classes need. With a base class, i have something bundling the classes into the same 'family'.

 

What is standard when there are requirements of classes to be used as template args? How are the requirements documented? In code, in comments somewhere, or in some external documentation? Or do you just copypaste the declaration of a working class and implement them? :P


o3o


#8 Álvaro   Crossbones+   -  Reputation: 13880

Like
0Likes
Like

Posted 13 June 2013 - 12:50 PM

Can you give your classes real names instead of things like "Foo"? It's very hard to discuss design decisions in a vacuum.



#9 SiCrane   Moderators   -  Reputation: 9662

Like
0Likes
Like

Posted 13 June 2013 - 01:11 PM

Generally, the documentation for the template says that the template arguments are required to satisfy certain criteria and somewhere that criteria is defined. For example, for the C++ standard library in C++03, the value types of containers are documented to be Assignable and CopyConstructible and references to where those requirements are documented are placed in the container documentation (sections 23.1 and 20.1.3 if anyone cares).



#10 Waterlimon   Crossbones+   -  Reputation: 2633

Like
0Likes
Like

Posted 13 June 2013 - 03:49 PM

As i dont have external documentation, i shall make an "example class" with method declarations and whatever else is required (no definitions), which i dont actually use anywhere.

Itll have the added benefit of letting me copypaste it when i need a new class that works with my templates.

Until something line concepts gets added, and 5 years from that so they are actually implemented ;P

o3o


#11 L. Spiro   Crossbones+   -  Reputation: 14197

Like
0Likes
Like

Posted 13 June 2013 - 04:26 PM

Waterlimon, since you plan never to actually instantiate classes of type Foo you are correct that you do not need virtual functions, and your method for run-time checking that methods have been implemented is fine, at least in debug mode.

 

But a better option for ensuring things work how you want them to work is to make the constructor of Foo protected rather than inheriting from it in a protected or private way—making the constructor protected ensures no future mistakes can occur when one day you accidentally forget and inherit from it in a public manner.

 

 

L. Spiro


It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#12 swiftcoder   Senior Moderators   -  Reputation: 10360

Like
4Likes
Like

Posted 13 June 2013 - 07:46 PM

There is a clever template trick to check the presence of members at runtime. This would allow you to at least check if interfaces are actually implemented.
 
Off the top of my head:
 
#include <iostream>

/*
interface Foo {
	foo();
	bar();
}
*/

template <typename T>
struct ensure_implements_foo {
	decltype(&T::foo) foo;
	decltype(&T::bar) bar;
};

class A {
public:
	int foo() {return 0;}
	void bar() {}
};

class B {
public:
};

int main() {
	ensure_implements_foo<A> checkA; // compiles fine
	ensure_implements_foo<B> checkB; // fails compilation, because B does not implement Foo
}
If you get cute with the template logic, you should be able to also confirm return types, and potentially even full function signatures.

Tristam MacDonald - Software Engineer @Amazon - [swiftcoding]


#13 swiftcoder   Senior Moderators   -  Reputation: 10360

Like
2Likes
Like

Posted 20 June 2013 - 12:05 AM


There is a clever template trick to check the presence of members at runtime.

You know, it now strikes me that this is a completely pointless exercise.

 

All the template magic in the world, and it still doesn't tell you anything more than you would know if you tried to call the function in the first place.


Tristam MacDonald - Software Engineer @Amazon - [swiftcoding]


#14 Álvaro   Crossbones+   -  Reputation: 13880

Like
2Likes
Like

Posted 20 June 2013 - 06:06 AM


All the template magic in the world, and it still doesn't tell you anything more than you would know if you tried to call the function in the first place.

 

Oh, but the obscure error message you would get with the method you posted is much more fun to track down. :)



#15 Juliean   GDNet+   -  Reputation: 2719

Like
0Likes
Like

Posted 20 June 2013 - 06:52 AM

When they say "code should be self-documenting", thats probably not what they mean biggrin.png Sorry for offtopic, here is some helpful advice:

 

Why don't you just use the pure virtual interface method, but put an ifdef around the virtual methods, eliminating them for release mode?

class Foo
{
#ifdef _DEBUG

virtual void test(void) = 0;
virtual void test2(void) = 0;
#endif
};

class Bar : public Foo
{
void test(void); // compile in both modes
// doesn't compile due to test2 missing in debug mode
};

This will at least remove the overhead of the virtual methods in release mode. I don't know if this is such a great idea code-style wise, and I personally don't think its necessary or adds anything, but you asked... what do the experienced guy say?


Edited by Juliean, 20 June 2013 - 06:54 AM.


#16 Tessellator   Members   -  Reputation: 656

Like
0Likes
Like

Posted 20 June 2013 - 06:57 AM

I've had these thoughts before and ultimately realized it was not necessary. Since you're not using virtual inheritance, you're not going to be storing all your objects in some big list of IThings (which is good), unless you implement your own runtime type identification and branch on the type (at which point you might as well use virtual). 

 

Instead, embrace that each of your Things is different and store them in different lists so you don't need to know the type. You can always document naming/interface schemes instead. As the others have said, just start writing code and let the compiler do the work for you. smile.png

 

T



#17 swiftcoder   Senior Moderators   -  Reputation: 10360

Like
2Likes
Like

Posted 20 June 2013 - 09:41 AM

Oh, but the obscure error message you would get with the method you posted is much more fun to track down. smile.png

You should rejoin the modern world, my friend, where template errors are no longer scary:

$ clang++ -std=c++11 -o foo foo.c++

foo.c++:12:18: error: no member named 'foo' in 'B'
    decltype(&T::foo) foo;
              ~~~^
foo.c++:28:30: note: in instantiation of template class 'ensure_implements_foo<B>' requested here
    ensure_implements_foo<B> checkB; // fails compilation, because B does not implement Foo
                             ^
foo.c++:13:18: error: no member named 'bar' in 'B'
    decltype(&T::bar) bar;
              ~~~^
2 errors generated.

Tristam MacDonald - Software Engineer @Amazon - [swiftcoding]


#18 Álvaro   Crossbones+   -  Reputation: 13880

Like
1Likes
Like

Posted 20 June 2013 - 10:00 AM

Oooohhh! Aaaahhhh!

 

Now I just have to convince my company to ditch g++. :)



#19 Matt-D   Crossbones+   -  Reputation: 1469

Like
0Likes
Like

Posted 23 June 2013 - 11:58 AM

Sounds like you may be interested in the Curiously Recurring Template Pattern (CRTP):

http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

http://eli.thegreenplace.net/2011/05/17/the-curiously-recurring-template-pattern-in-c/

http://stackoverflow.com/questions/262254/crtp-to-avoid-dynamic-polymorphism

http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Curiously_Recurring_Template_Pattern

http://accu.org/index.php/journals/296

 

Alternatively, check out the non-virtual interface (NVI) pattern:

http://en.wikipedia.org/wiki/Non-virtual_interface_pattern

http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface

http://stackoverflow.com/questions/6481260/non-virtual-interface-design-pattern-question-in-c-c

http://herbsutter.com/2013/05/22/gotw-5-solution-overriding-virtual-functions/






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS