CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12

Thread: Semantics

Threaded View

  1. #1
    Join Date
    Aug 2008
    Posts
    902

    Semantics

    I think that an important thing to accomplish in any API is to separate the interface from the implementation. One way of doing this is through the pimpl idiom. Another way is through the use of Interfaces, which are essentially Pure Abstract Classes. I like this approach a lot, because it allows for late binding and completely hides implementation (keep those public header files light and devoid of implementation details).

    Example:

    Code:
    //Window.h - part of the public API
    
    class IWindow
    {
    public:
        static IWindow* New(int width, int height);
        virtual ~IWindow() {}
        virtual void setSize(int width, int height) = 0;
        virtual void setTitle(const std::string& title) = 0;
    }; //notice no implementation details here
    
    //MyWindowImpl.h - private header
    
    #include "Window.h"
    class MyWindowImpl : public IWindow
    {
    public:
        MyWindowImpl(int width, int height);
        void setSize(int width, int height);
        void setTitle(const std::string& title);
    };
    
    //Window.cpp - code file, not a part of the public API
    
    #include "Window.h"
    #include "MyWindowImpl.h"
    
    IWindow* IWindow::New(int width, int height)
    {
        //we could dynamically choose which type of window to return
        return new MyWindowImpl(int width, int height);
    }
    
    //example usage
    
    #include "Widnow.h"
    
    int main()
    {
        IWindow* wnd = IWindow::New(640, 480);
        wnd->setTitle("Hello, World!");
        delete wnd;
    }
    That's great, because the only thing the user need be exposed to is the interface. However, the one disadvantage is that you are stuck with pointers. I think most modern C++ programmers try to avoid pointers as much as possible. The STL for example, is an API mostly devoid of pointers. We don't create pointers to string or stream objects after all. I think most programmers expect a good modern API to have value semantics similar to:

    Code:
    int main()
    {
        Window wnd(640, 480);
        wnd.setTitle("Hello, World!");
    }
    They want to be able to create their objects on the stack and benefit from RAII. Wouldn't it be nice if we could have our cake and eat it too? One solution would be to use smart pointers. We could do this instead:

    Code:
    //Window.h
    class IWindow
    {
    public:
        typedef std::shared_ptr<IWindow> Ptr;
        ...
    }
    
    //example
    
    int main()
    {
        IWindow::Ptr wnd(IWindow::New(640, 480));
        wnd->setTitle("Hello, World!");
    }
    You still have pointer semantics, but at least you don't have to worry about managing it's lifetime. However, I was working on a slightly different approach which may bring the it a bit closer to value semantics.

    Code:
    //Window.h
    
    #include "SmartRef.h"
    
    class IWindow
    {
    public:
    	virtual ~IWindow() {}
    	virtual void setSize(int width, int height) = 0;
    	virtual void setTitle(const std::string& title) = 0;
    }; //very clean interface definition
    
    typedef SmartRef<IWindow, int, int> Window;
    
    
    //SmartRef.h
    
    template <class T, class... InitArgs>
    class SmartRef
    {
    public:
    	typedef SmartRef<T, InitArgs...> ref_type;
    	static ref_type New(InitArgs...) {}
    	SmartRef(InitArgs... args)
    	{
    		*this = ref_type::New(args...);
    	}
    	SmartRef(T* ptr)
    		:	_ptr(ptr)
    	{}
    	T* operator->() { return _ptr.get(); }
    private:
    	std::shared_ptr<T> _ptr;
    };
    
    
    //Window.cpp
    
    #include "MyWindowImpl.h"
    
    template<>
    Window Window::New(int width, int height)
    {
    	return new MyWindowImpl(width, height);
    }
    
    
    //example usage
    
    #include "Window.h"
    
    int main()
    {
        Window wnd(640, 480); //alternatively Window wnd = Window::New(640, 480);
        wnd->setTitle("Hello, World!");
    }
    You are still stuck using the pointer operator, but everything else about it is like value semantics. These semantics look similar to Google's V8 API.

    What exactly are your thoughts?
    Last edited by Chris_F; October 30th, 2011 at 08:22 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured