How do I setup a class that represents an interface? Is this just an abstract base class?
To expand on the answer by bradtgmurray, you may want to make one exception to the pure virtual method list of your interface by adding a virtual destructor. This allows you to pass pointer ownership to another party without exposing the concrete derived class. The destructor doesn't have to do anything, because the interface doesn't have any concrete members. It might seem contradictory to define a function as both virtual and inline, but trust me - it isn't.
class IDemo
{
public:
virtual ~IDemo() {}
virtual void OverrideMe() = 0;
};
class Parent
{
public:
virtual ~Parent();
};
class Child : public Parent, public IDemo
{
public:
virtual void OverrideMe()
{
//do stuff
}
};
You don't have to include a body for the virtual destructor - it turns out some compilers have trouble optimizing an empty destructor and you're better off using the default.
=0
) destructor with a body. The advantage here is that the compiler can, theoretically, see that vtable has no valid members now, and discard it altogether. With a virtual destructor with a body, said destructor can be called (virtually) e.g. in the middle of construction via this
pointer (when constructed object is still of Parent
type), and therefore the compiler has to provide a valid vtable. So if you don't explicitly call virtual destructors via this
during construction :) you can save on code size. –
Teddytedeschi throw
from the constructor of a derived class. –
Briquet Base
<- Derived
<- MostDerived
. You are in Derived ctor. You call a global function that takes a Base*
argument, passing it this
. That function can explicitly invoke the destructor via the pointer, and it has to be dispatched virtually. –
Teddytedeschi MostDerived
constructor getting very unhappy. At least with destroying via throw
the remainder of the construction is bypassed. –
Briquet MostDerived
, but I don't see anything that would make e.g. this->~Foo()
in a ctor UB all by itself. Consider the case where you destruct it, and then never return to the ctor (e.g. just sit there in an infinite loop, taking and processing input). Inside that loop, your behavior would be well-defined, so far as I can see. –
Teddytedeschi override
keyword to allow for compile-time argument and return value type checking. For example, in the declaration of Child virtual void OverrideMe() override;
–
Passe *a = *b
but I grant you it's not common. –
Briquet Child
, is it still necessary to write OverrideMe()
as virtual void
? –
Samaveda virtual
is not necessary since the base class declaration already made it virtual, but it's good practice to be consistent. void
is still necessary. –
Briquet Make a class with pure virtual methods. Use the interface by creating another class that overrides those virtual methods.
A pure virtual method is a class method that is defined as virtual and assigned to 0.
class IDemo
{
public:
virtual ~IDemo() {}
virtual void OverrideMe() = 0;
};
class Child : public IDemo
{
public:
virtual void OverrideMe()
{
// do stuff
}
};
override
in C++11 –
Hiram Child::OverrideMe()
as virtual
, @Cemre, because IDemo::OverrideMe()
makes Child::OverrideMe()
implicitly virtual
. Having an indication that it's a virtual function (such as virtual
, or better yet, override
in C++11 or later) will serve as a reminder for programmers, with override
in particular also helping the compiler check that it does indeed override something. –
Gynoecium The whole reason you have a special Interface type-category in addition to abstract base classes in C#/Java is because C#/Java do not support multiple inheritance.
C++ supports multiple inheritance, and so a special type isn't needed. An abstract base class with no non-abstract (pure virtual) methods is functionally equivalent to a C#/Java interface.
java.lang.Thread
class and java.lang.Runnable
interface, which exists just because you can not extend Thread
along with another base. From documentation it may seem that it's provided for your choice, but I was once forced to use Runnable
because of lack of multiple inheritance. –
Bursiform Thread
instance. Multiple inheritance can be bad design as well as composition. It all depends on case. –
Bursiform abstract
keyword in C++. –
Genitalia There is no concept of "interface" per se in C++. AFAIK, interfaces were first introduced in Java to work around the lack of multiple inheritance. This concept has turned out to be quite useful, and the same effect can be achieved in C++ by using an abstract base class.
An abstract base class is a class in which at least one member function (method in Java lingo) is a pure virtual function declared using the following syntax:
class A
{
virtual void foo() = 0;
};
An abstract base class cannot be instantiated, i. e. you cannot declare an object of class A. You can only derive classes from A, but any derived class that does not provide an implementation of foo()
will also be abstract. In order to stop being abstract, a derived class must provide implementations for all pure virtual functions it inherits.
Note that an abstract base class can be more than an interface, because it can contain data members and member functions that are not pure virtual. An equivalent of an interface would be an abstract base class without any data members, and containing only pure virtual functions.
And, as Mark Ransom pointed out, an abstract base class should provide a virtual destructor, just like any base class, for that matter.
A good way to think of this is in terms of inheriting an interface vs. inheriting an implementation. In C++ you can either inherit both interface and implementation together (public inheritance) or you can inherit only the implementation (private inheritance). In Java you have the option of inheriting just the interface, without an implementation.
class Button; class Image; class ClickableIcon : public Button, public Image {};
. If they're designed properly, Image will supply the graphics functionality and Button will supply the interactive functionality, with no overlap that could cause issues, while ClickableIcon itself handles the functionality the button is for. –
Gynoecium Button
provides the interactive code, Image
provides the graphics code, and ClickableIcon
provides code specific to itself, as well as any code needed to weld the two parent classes together. As long as the two classes are designed properly, and have no overlapping member names, the class should be entirely viable, and easier to implement than if one or both was an interface. –
Gynoecium As far I could test, it is very important to add the virtual destructor. I'm using objects created with new
and destroyed with delete
.
If you do not add the virtual destructor in the interface, then the destructor of the inherited class is not called.
class IBase {
public:
virtual ~IBase() {}; // destructor, use it to call destructor of the inherit classes
virtual void Describe() = 0; // pure virtual method
};
class Tester : public IBase {
public:
Tester(std::string name);
virtual ~Tester();
virtual void Describe();
private:
std::string privatename;
};
Tester::Tester(std::string name) {
std::cout << "Tester constructor" << std::endl;
this->privatename = name;
}
Tester::~Tester() {
std::cout << "Tester destructor" << std::endl;
}
void Tester::Describe() {
std::cout << "I'm Tester [" << this->privatename << "]" << std::endl;
}
void descriptor(IBase * obj) {
obj->Describe();
}
int main(int argc, char** argv) {
std::cout << std::endl << "Tester Testing..." << std::endl;
Tester * obj1 = new Tester("Declared with Tester");
descriptor(obj1);
delete obj1;
std::cout << std::endl << "IBase Testing..." << std::endl;
IBase * obj2 = new Tester("Declared with IBase");
descriptor(obj2);
delete obj2;
// this is a bad usage of the object since it is created with "new" but there are no "delete"
std::cout << std::endl << "Tester not defined..." << std::endl;
descriptor(new Tester("Not defined"));
return 0;
}
If you run the previous code without virtual ~IBase() {};
, you will see that the destructor Tester::~Tester()
is never called.
delete
keyword in when deleting the object as an IBase
. –
Retinoscope My answer is basically the same as the others but I think there are two other important things to do:
Declare a virtual destructor in your interface or make a protected non-virtual one to avoid undefined behaviours if someone tries to delete an object of type
IDemo
.Use virtual inheritance to avoid problems whith multiple inheritance. (There is more often multiple inheritance when we use interfaces.)
And like other answers:
- Make a class with pure virtual methods.
Use the interface by creating another class that overrides those virtual methods.
class IDemo { public: virtual void OverrideMe() = 0; virtual ~IDemo() {} }
Or
class IDemo { public: virtual void OverrideMe() = 0; protected: ~IDemo() {} }
And
class Child : virtual public IDemo { public: virtual void OverrideMe() { //do stuff } }
In C++11 you can easily avoid inheritance altogether:
struct Interface {
explicit Interface(SomeType& other)
: foo([=](){ return other.my_foo(); }),
bar([=](){ return other.my_bar(); }), /*...*/ {}
explicit Interface(SomeOtherType& other)
: foo([=](){ return other.some_foo(); }),
bar([=](){ return other.some_bar(); }), /*...*/ {}
// you can add more types here...
// or use a generic constructor:
template<class T>
explicit Interface(T& other)
: foo([=](){ return other.foo(); }),
bar([=](){ return other.bar(); }), /*...*/ {}
const std::function<void(std::string)> foo;
const std::function<void(std::string)> bar;
// ...
};
In this case, an Interface has reference semantics, i.e. you have to make sure that the object outlives the interface (it is also possible to make interfaces with value semantics).
These type of interfaces have their pros and cons:
- They require more memory than inheritance based polymorphism.
- They are in general faster than inheritance based polymorphism.
- In those cases in which you know the final type, they are much faster! (some compilers like gcc and clang perform more optimizations in types that do not have/inherit from types with virtual functions).
Finally, inheritance is the root of all evil in complex software design. In Sean Parent's Value Semantics and Concepts-based Polymorphism (highly recommended, better versions of this technique are explained there) the following case is studied:
Say I have an application in which I deal with my shapes polymorphically using the MyShape
interface:
struct MyShape { virtual void my_draw() = 0; };
struct Circle : MyShape { void my_draw() { /* ... */ } };
// more shapes: e.g. triangle
In your application, you do the same with different shapes using the YourShape
interface:
struct YourShape { virtual void your_draw() = 0; };
struct Square : YourShape { void your_draw() { /* ... */ } };
/// some more shapes here...
Now say you want to use some of the shapes that I've developed in your application. Conceptually, our shapes have the same interface, but to make my shapes work in your application you would need to extend my shapes as follows:
struct Circle : MyShape, YourShape {
void my_draw() { /*stays the same*/ };
void your_draw() { my_draw(); }
};
First, modifying my shapes might not be possible at all. Furthermore, multiple inheritance leads the road to spaghetti code (imagine a third project comes in that is using the TheirShape
interface... what happens if they also call their draw function my_draw
?).
Update: There are a couple of new references about non-inheritance based polymorphism:
- Sean Parent's Inheritance is the base class of evil talk.
- Sean Parent's Value-semantics and concept-based polymorphism talk.
- Pyry Jahkola's Inheritance free polymorphism talk and the poly library docs.
- Zach Laine's Pragmatic Type Erasure: Solving OOP Problems with an Elegant Design Pattern talk.
- Andrzej's C++ blog - Type Erasure parts i, ii, iii, and iv.
- Runtime Polymorphic Generic Programming—Mixing Objects and Concepts in ConceptC++
- Boost.TypeErasure docs
- Adobe Poly docs
- Boost.Any, std::any proposal (revision 3), Boost.Spirit::hold_any.
Circle
class is a poor design. You should use Adapter
pattern in such cases. Sorry if it will sound a little bit harsh, but try to use some real life library like Qt
before making judgements about inheritance. Inheritance makes life much easier. –
Bursiform Adapter
pattern? I'm interested to see its advantages. –
Uncanonical Square
isn't already there? Foreknowledge? That's why it is detached from reality. And in reality if you choose to rely on "MyShape" library you can adopt to its interface from the very beginning. In shapes example there are many nonsenses (one of which is that you have two Circle
structs), but adapter would look something like that -> ideone.com/UogjWk –
Bursiform Adapter
pattern. Providing implementation in interface like one in your answer means that I have to provide all virtual methods, which otherwise could be simply inherited. –
Bursiform object_t
internals nor I can't inherit after it? From what I see, I have to implement draw()
function from scratch on my own and I am not binded to concept_t
interface. Also, with virtual methods I can have default implementations, which I can override or not. –
Bursiform gnzlbg::vector
in your class and I provide interface with my custom doc::vector
and you have to convert input and output to your internals. Where's our code re-use and efficiency if you need to convert them? –
Bursiform doc::vector
or gnzlbg::vector
on interface premise. You should learn how to properly use inheritance, because what you are saying now, does not make any sense! –
Bursiform All good answers above. One extra thing you should keep in mind - you can also have a pure virtual destructor. The only difference is that you still need to implement it.
Confused?
--- header file ----
class foo {
public:
foo() {;}
virtual ~foo() = 0;
virtual bool overrideMe() {return false;}
};
---- source ----
foo::~foo()
{
}
The main reason you'd want to do this is if you want to provide interface methods, as I have, but make overriding them optional.
To make the class an interface class requires a pure virtual method, but all of your virtual methods have default implementations, so the only method left to make pure virtual is the destructor.
Reimplementing a destructor in the derived class is no big deal at all - I always reimplement a destructor, virtual or not, in my derived classes.
You can also consider contract classes implemented with the NVI (Non Virtual Interface Pattern). For instance:
struct Contract1 : boost::noncopyable
{
virtual ~Contract1() = default;
void f(Parameters p) {
assert(checkFPreconditions(p)&&"Contract1::f, pre-condition failure");
// + class invariants.
do_f(p);
// Check post-conditions + class invariants.
}
private:
virtual void do_f(Parameters p) = 0;
};
...
class Concrete : public Contract1, public Contract2
{
private:
void do_f(Parameters p) override; // From contract 1.
void do_g(Parameters p) override; // From contract 2.
};
If you're using Microsoft's C++ compiler, then you could do the following:
struct __declspec(novtable) IFoo
{
virtual void Bar() = 0;
};
class Child : public IFoo
{
public:
virtual void Bar() override { /* Do Something */ }
}
I like this approach because it results in a lot smaller interface code and the generated code size can be significantly smaller. The use of novtable removes all reference to the vtable pointer in that class, so you can never instantiate it directly. See the documentation here - novtable.
novtable
over standard virtual void Bar() = 0;
–
Thievish = 0;
which I've added). Read the documentation if you don't understand it. –
Fanatic = 0;
and assumed it was just a non-standard way of doing exactly the same. –
Thievish A little addition to what's written up there:
First, make sure your destructor is also pure virtual
Second, you may want to inherit virtually (rather than normally) when you do implement, just for good measures.
class Base { public: ~Base() = 0; }; Base::~Base() {}
, to allow the compiler to generate default constructors for derived classes –
Gynoecium In C++20, you can use a concept
instead of a class.
It is more efficient than inheritance.
template <class T>
concept MyInterface = requires (T t) {
{ t.interfaceMethod() };
};
class Implementation {
public:
void interfaceMethod();
};
static_assert(MyInterface<Implementation>);
Then you can use it in a function:
void myFunction(MyInterface auto& arg);
The limitation is that you cannot use it in a container.
While it's true that virtual
is the de-facto standard to define an interface, let's not forget about the classic C-like pattern, which comes with a constructor in C++:
struct IButton
{
void (*click)(); // might be std::function(void()) if you prefer
IButton( void (*click_)() )
: click(click_)
{
}
};
// call as:
// (button.*click)();
This has the advantage that you can re-bind events runtime without having to construct your class again (as C++ does not have a syntax for changing polymorphic types, this is a workaround for chameleon classes).
Tips:
- You might inherit from this as a base class (both virtual and non-virtual are permitted) and fill
click
in your descendant's constructor. - You might have the function pointer as a
protected
member and have apublic
reference and/or getter. - As mentioned above, this allows you to switch the implementation in runtime. Thus it's a way to manage state as well. Depending on the number of
if
s vs. state changes in your code, this might be faster thanswitch()
es orif
s (turnaround is expected around 3-4if
s, but always measure first. - If you choose
std::function<>
over function pointers, you might be able to manage all your object data withinIBase
. From this point, you can have value schematics forIBase
(e.g.,std::vector<IBase>
will work). Note that this might be slower depending on your compiler and STL code; also that current implementations ofstd::function<>
tend to have an overhead when compared to function pointers or even virtual functions (this might change in the future).
I'm still new in C++ development. I started with Visual Studio (VS).
Yet, no one seems to mentioned the __interface
in VS (.NET). I am not very sure if this is a good way to declare an interface. But it seems to provide an additional enforcement (mentioned in the documents). Such that you don't have to explicitly specify the virtual TYPE Method() = 0;
, since it will be automatically converted.
__interface IMyInterface {
HRESULT CommitX();
HRESULT get_X(BSTR* pbstrName);
};
However, I don't use it because I am concern about the cross platform compilation compatibility, since it only available under .NET.
If anyone do have anything interesting about it, please share. :-)
Thanks.
In case you only want static binding of an interface(no virtual, no instances of the interface type itself, interface only act as a guide):
#include <iostream>
#include <string>
// Static binding interface
// Notice: instantiation of this interface should be usefuless and forbidden.
class IBase {
protected:
IBase() = default;
~IBase() = default;
public:
// Methods that must be implemented by the derived class
void behaviorA();
void behaviorB();
void behaviorC() {
std::cout << "This is an interface default implementation of bC().\n";
};
};
class CCom : public IBase {
std::string name_;
public:
void behaviorA() { std::cout << "CCom bA called.\n"; };
};
class CDept : public IBase {
int ele_;
public:
void behaviorB() { std::cout << "CDept bB called.\n"; };
void behaviorC() {
// Overwrite the interface default implementation
std::cout << "CDept bC called.\n";
IBase::behaviorC();
};
};
int main(void) {
// Forbid the instantiation of the interface type itself.
// GCC error: ‘constexpr IBase::IBase()’ is protected within this context
// IBase o;
CCom acom;
// If you want to use these interface methods, you need to implement them in
// your derived class. This is controled by the interface definition.
acom.behaviorA();
// ld: undefined reference to `IBase::behaviorB()'
// acom.behaviorB();
acom.behaviorC();
CDept adept;
// adept.behaviorA();
adept.behaviorB();
adept.behaviorC();
// adept.IBase::behaviorC();
}
Here is the definition of abstract class
in c++ standard
n4687
13.4.2
An abstract class is a class that can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it. A class is abstract if it has at least one pure virtual function.
class Shape
{
public:
// pure virtual function providing interface framework.
virtual int getArea() = 0;
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
class Rectangle: public Shape
{
public:
int getArea()
{
return (width * height);
}
};
class Triangle: public Shape
{
public:
int getArea()
{
return (width * height)/2;
}
};
int main(void)
{
Rectangle Rect;
Triangle Tri;
Rect.setWidth(5);
Rect.setHeight(7);
cout << "Rectangle area: " << Rect.getArea() << endl;
Tri.setWidth(5);
Tri.setHeight(7);
cout << "Triangle area: " << Tri.getArea() << endl;
return 0;
}
Result: Rectangle area: 35 Triangle area: 17
We have seen how an abstract class defined an interface in terms of getArea() and two other classes implemented same function but with different algorithm to calculate the area specific to the shape.
© 2022 - 2024 — McMap. All rights reserved.