Thread: Interface in C++

  1. #1
    Registered User
    Join Date
    Dec 2015
    Posts
    92

    Interface in C++

    Hello guys, I want to make Serial communication interface in C++, I know there is no real interface like in Java/C# so I wanted to make class SerialCommuncation fully abstract.

    Code:
    
    class SerialCommuncation
    {
        public:
    
    
            virtual int write(CircularBuffer& txQueue, unsigned char* bytes) = 0;
            virtual bool writeByte(CircularBuffer& txQueue, unsigned char byte);
            virtual bool write(CircularBuffer& txQueue, unsigned char byte, unsigned char offset, unsigned char length) = 0;
            virtual void println(CircularBuffer& queue, unsigned char* bytes) = 0;
            virtual bool readByte(CircularBuffer& queue, unsigned char* byte) = 0;
            virtual unsigned char* read(CircularBuffer& queue) = 0;
    };
    Code:
    
    class Transmitter : public SerialCommuncation
    {
        public:
    
    
            bool writeByte (CircularBuffer& txQueue, unsigned char byte) 
            {
                // wait until queue is empty
                while (txQueue.isEmpty());
    
    
                // check if byte is successfully pushed into queue
                if (txQueue.enqueue(byte))
                    return true;
                return false;
            }
    
    
            bool write(CircularBuffer& txQueue, unsigned char* bytes, unsigned char offset, unsigned char length) 
            {
                int bytesWrittenCnt = 0;
                // wait until all data is send to the buffer
                // Problem: što ako je RED popunjen, a svi bytovi nisu writeani
                isInterruptEnabled = false;
                for (int i = offset; i < length; i++)
                {
                    if (writeByte(txQueue, bytes[bytesWrittenCnt]))
                        bytesWrittenCnt++;
                }
    
    
                isInterruptEnabled = true;
                return bytesWrittenCnt;
            }
    
    
            int write (CircularBuffer& txQueue, unsigned char* bytes) 
            {
                int bytesWrittenCnt = 0;
                isInterruptEnabled = false;
                // wait untill all data is send to the buffer
                // Problem: što ako je RED popunjen, a svi bytovi nisu writeani
                while (bytes[bytesWrittenCnt] != '\0')
                {
                    if (writeByte(txQueue, bytes[bytesWrittenCnt]))
                        bytesWrittenCnt++;
                }
    
    
                isInterruptEnabled = true;
                return bytesWrittenCnt;
            }
    };

    Code:
    
    class CircularBuffer
    {
        private:
            int availableItems;
        public:
            int head;
            int tail;
            unsigned char buffer[BUFFER_SIZE];
            int dequeuedElement;
    
    
            friend void RX_ISR();
            friend void TX_ISR();
    
    
            CircularBuffer()
            {
                head = 0;
                tail = 0;
                dequeuedElement = 0;
                availableItems = 0;
                for (int i = 0; i < BUFFER_SIZE; ++i)
                {
                    buffer[i] = 0;
                }
            }
    
    
            bool isAvailable()
            {
    
    
                if (head - tail)
                {
                    return true;
                }
                return false;
            }
    
    
            int getAvailableElements()
            {
                int size;
                if (head == 0 && tail == 0)
                    size = 0;
                else
                    size = head > tail ? (BUFFER_SIZE - head + tail) : (tail - head);
    
    
                return size;
            }
    
    
            bool isEmpty()
            {
                if (head - tail == 0)
                {
                    return true;
                }
                return false;
            }
    
    
            bool isFull(int tempTail)
            {
    
    
                if (this->head - tempTail)
                {
                    return false;
                }
                return true;
            }
    
    
            bool enqueue(int element)
            {
                int tempTail = (tail + 1) & BUFFER_MASK;
                if (isFull(tempTail))
                {
                    return false;
                }
                tail = tempTail;
                buffer[tail] = element;
                return true;
            }
    
    
            bool dequeue(unsigned char* byte)
            {
                if (isEmpty())
                {
                    return false;
                }
                head = (head + 1) & BUFFER_MASK;
                *byte = buffer[head];
                return true;
            }
    };

    Code:
    
    int main()
    {
        CircularBuffer rxQueue;
        CircularBuffer txQueue;
        Transmitter transmitter;
    }
    Compiler gives following errors:


    Error (active)
    object of abstract class type "Transmitter" is not allowed: CircularBuffer
    object of abstract class type "Transmitter" is not allowed: CircularBufferpure virtual function "SerialCommuncation::write(CircularBuffer &txQueue, unsigned char byte, unsigned char offset, unsigned char length)" has no overrider
    pure virtual function "SerialCommuncation: println" has no overrider
    pure virtual function "SerialCommuncation::readByte" has no overrider
    pure virtual function "SerialCommuncation::read" has no overrider




    So somehow compiler thinks that class Transmitter is abstract . I am not sure why it is happening since I have implementation of the methods in class Transmitter and I have overriden them.
    Is problem lying in '=0'.
    Last edited by Salem; 03-02-2017 at 05:34 AM. Reason: fixed tag

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    1. You need to implement ALL your virtual methods in the derived class.

    2. You need to check your prototypes carefully.
    Re
    virtual bool write(CircularBuffer& txQueue, unsigned char byte, unsigned char offset, unsigned char length) = 0;
    vs
    bool write(CircularBuffer& txQueue, unsigned char* bytes, unsigned char offset, unsigned char length)

    3. Why isn't this pure?
    virtual bool writeByte(CircularBuffer& txQueue, unsigned char byte);
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by High Voltage
    So somehow compiler thinks that class Transmitter is abstract . I am not sure why it is happening since I have implementation of the methods in class Transmitter and I have overriden them.
    Read the compiler's error message:
    Code:
    object of abstract class type "Transmitter" is not allowed: CircularBufferpure virtual function "SerialCommuncation::write(CircularBuffer &txQueue, unsigned char byte, unsigned char offset, unsigned char length)" has no overrider
    So, contrary to your claim, you did not override one of the pure virtual functions. Actually, you came close:
    Code:
    // in SerialCommuncation:
    virtual bool write(CircularBuffer& txQueue, unsigned char byte, unsigned char offset, unsigned char length) = 0;
    // in Transmitter with the virtual keyword added so they line up, or not:
    virtual bool write(CircularBuffer& txQueue, unsigned char* bytes, unsigned char offset, unsigned char length)
    Since an unsigned char second parameter is not a pointer to unsigned char second parameter, this member function in Transmitter does not override the virtual member function of SerialCommuncation. Rather, it is an overload.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Dec 2015
    Posts
    92
    Looks like I didn't understood that placing '=0' makes method pure virtual.
    Why do we put '=0' (besides compiler distinquishing virtual from pure virtual method), what compiler does when he sees '=0'.


    I splitted original interface into two interfaces


    #1 Interface


    Code:
    
    class Transmitter
    {
        public:
            virtual int write(unsigned char* bytes) = 0;
            virtual bool writeByte(unsigned char byte) = 0;
            virtual bool write(unsigned char* byte, unsigned char offset, unsigned char length) = 0;
    };

    Code:
    
    class SerialCommTransmitter : public Transmitter
    {
        private:
            CircularBuffer txQueue;
        
        public:
            bool writeByte(unsigned char byte)
            {
                // wait until queue is empty
                while (txQueue.isEmpty());
    
    
                // check if byte is successfully pushed into queue
                if (txQueue.enqueue(byte))
                    return true;
                return false;
            }
    
    
            bool write(unsigned char* bytes, unsigned char offset, unsigned char length)
            {
                int bytesWrittenCnt = 0;
                // wait until all data is send to the buffer
                // Problem: što ako je RED popunjen, a svi bytovi nisu writeani
                isInterruptEnabled = false;
                for (int i = offset; i < length; i++)
                {
                    if (writeByte(bytes[bytesWrittenCnt]))
                        bytesWrittenCnt++;
                }
    
    
                isInterruptEnabled = true;
                return bytesWrittenCnt;
            }
    
    
            int write(unsigned char* bytes)
            {
                int bytesWrittenCnt = 0;
                isInterruptEnabled = false;
                // wait untill all data is send to the buffer
                // Problem: što ako je RED popunjen, a svi bytovi nisu writeani
                while (bytes[bytesWrittenCnt] != '\0')
                {
                    if (writeByte(bytes[bytesWrittenCnt]))
                        bytesWrittenCnt++;
                }
    
    
                isInterruptEnabled = true;
                return bytesWrittenCnt;
            }
    
    
    };



    #2 Inteface


    Code:
    
    class Receiver
    {
        public:
            virtual bool readByte(unsigned char* byte) = 0;
            virtual unsigned char* read() = 0;
    };

    Code:
    
    class SerialCommReceiver : public Receiver
    {
            private:
                CircularBuffer rxQueue;
    
    
            public:
                bool readByte(unsigned char* byte)
                {
                    if (!rxQueue.isEmpty())
                    {
                        rxQueue.dequeue(byte);
                        return true;
                    }
                    return false;
                }
    
    
                unsigned char* read()
                {
                    unsigned char bytesWrittenCnt = 0;
                    unsigned char* byte = (unsigned char*)malloc(sizeof(unsigned char));
    
    
                    // PROBLEM: ne znamo koliko cemo dugo cekati na read jer se kroz citanje može konstantno dešavati 
                    // receive interrupt, te stoga ne znamo koliko veliki buffer moramo alocirati
                    unsigned char rxBuffer[BUFFER_SIZE];
    
    
                    while (readByte(byte))
                    {
                        rxBuffer[bytesWrittenCnt++] = *byte;
                    }
    
    
                    return rxBuffer;
                }
    };

    Code:
    class SerialPort
    {
        private:
            unsigned int baudRate;
            SerialCommReceiver serialReceiver;
            SerialCommTransmitter serialTransmitter;
    
    
        public:
            SerialPort(int baudRate)
            {
                this->baudRate = baudRate;
            }    
            unsigned char* read()
            {
                return serialReceiver.read();
            }
    
    
    };

    If I want to use constant object field in any of classes without passing reference to the constructor do I need to instantiate them like in Java/C# with new operator?
    Code:
    class SerialPort
    {
        private:
            unsigned int baudRate;
            SerialCommReceiver serialReceiver = new SerialCommReceiver();
            SerialCommTransmitter serialTransmitter = new SerialCommTransmitter();
    
    
        public:
            SerialPort(int baudRate)
            {
                this->baudRate = baudRate;
            }    
            unsigned char* read()
            {
                return serialReceiver.read();
            }
    
    
    };



    Also if I want to use my class methods with Interrupts and I am interested if the following approach work:


    Since ATMega micrcocontroller header file where all interrupt ISR functions are declared is written in C I use extern "C" keyword


    Code:
    extern "C" void UART0_UDRE_vect(void) __attribute__ ((signal));
    extern "C" void USART0_RX_vect(void) __attribute__ ((signal));

    Code:
    class SerialPort
    {
        private:
            unsigned int baudRate;
            SerialCommReceiver serialReceiver;
            SerialCommTransmitter serialTransmitter;
            static SerialPort* rxPointer;
            static SerialPort* txPointer;
    
    
        public:
            friend void UART0_UDRE_vect(void);
            friend void USART0_RX_vect(void);
    
    
            SerialPort(int baudRate)
            {
                this->baudRate = baudRate;
                rxPointer = this;
                txPointer = this;
            }    
    
    
            unsigned char* read()
            {
                return serialReceiver.read();
            }
    
    
    };

    And then using SerialPort class methods via SerialPort pointers in ISRs


    Code:
    void UART0_UDRE_vect(void);
    {
        unsigned char* byte = (unsigned char*)malloc(sizeof(unsigned char)); // je li ova varijabla treba biti static volatile ?
    
    
                                                                             /* Check if all data is transmitted */
        if (txPointer->read(byte)))
        {
            UDR1 = *byte;
        }
    }
    Last edited by High Voltage; 03-02-2017 at 02:49 PM.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by High Voltage
    Why do we put '=0' (besides compiler distinquishing virtual from pure virtual method), what compiler does when he sees '=0'.
    The entire purpose is to designate the member function as pure virtual. Exactly what the compiler does is of course compiler dependent.

    Quote Originally Posted by High Voltage
    I splitted original interface into two interfaces
    It makes sense to split fat interfaces to thin ones. However, your interface classes should have virtual destructors, otherwise there's the risk that an object of a derived class might be destroyed via a pointer to your interface class.

    If you want to go through the trouble of defining interface classes and inheriting from them though, I wonder why you aren't making use of them.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Dec 2015
    Posts
    92
    Does a class which implements interface, need to have virtual methods?

    Code:
    class Transmitter
    {
    	public:
    		virtual ~Transmitter() {}
    		virtual int write(unsigned char* bytes) = 0;
    		virtual bool writeByte(unsigned char byte) = 0;
    		virtual bool write(unsigned char* byte, unsigned char offset, unsigned char length) = 0;
    };
    Code:
    class SerialCommTransmitter : public Transmitter
    {
    	private:
    		CircularBuffer txQueue;
    
    
    	public:
    		virtual bool writeByte(unsigned char byte);
    		virtual bool write(unsigned char* bytes, unsigned char offset, unsigned char length);
    		virtual int write(unsigned char* bytes);
    };
    Should inline keyword be used with virtual functions

    Code:
    inline virtual bool writeByte(unsigned char byte);

  7. #7
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Why do you think inline should be there in the first place?

  8. #8
    Registered User
    Join Date
    Dec 2015
    Posts
    92
    Quote Originally Posted by MutantJohn View Post
    Why do you think inline should be there in the first place?
    Yeah you are right, I was just giving an example. It would be better to make interrupt handler methods inline.


    I am experiencing a weird problem when calling a enqueue() method from ISR function.
    It seems like after dequeing an element, newly calculated head never gets stored in my object (class CircularBuffer) and everytime I try to dequeue a new element, head seems to be 0, unlike tail.
    Code:
    this->head = (this->head + 1) & BUFFER_MASK;
    here is the whole method
    Code:
    bool CircularQueue::dequeue(unsigned char* byte)
    {
        if (isEmpty())
        {
            return false;
        }
        this->head = (this->head + 1) & BUFFER_MASK;
        *byte = buffer[this->head];
        return true;
    }
    Here is ISR where serialPortPointer is a static pointer to a class SerialPort
    Code:
    static SerialPort* serialPortPointer;
    And serialPortPointer is assigned to this pointer in the SerialPort class constructor

    Code:
    void UART0_UDRE_vect(void)
    {
        unsigned char* tempByte = (unsigned char*)malloc(sizeof(unsigned char));
        // Check if all data is transmitted 
        if (SerialPort::serialPortPointer->serialTransmitter.getTxQueue().dequeue(tempByte))
        {
            UDR1 = *tempByte;
        }
        free(tempByte);
    }
    And here is function handler

    Code:
    void SerialPort::handle_UDRE_IRQ(unsigned char* tempByte)
    {
        SerialPort::serialTransmitter.getTxQueue().dequeue(tempByte);
    }
    The enqueue method worked without using static class pointer.

  9. #9
    Registered User
    Join Date
    Dec 2015
    Posts
    92
    Okay figured it out when I use getter to dequeue an element variable head of class CircularQueue never gets incremented

    So actually having rxQueue public in class SerialCommTransmitter and using it without having getter produces right result txQueue.head gets updated after every function call (void UART0_UDRE_vect(void))

    Code:
    class SerialCommTransmitter : public Transmitter
    {
        private:
            //CircularQueue txQueue;
    
    
        public:
            //CircularQueue getTxQueue();
            // CHANGED THIS FIELD INTO PUBLIC
            CircularQueue txQueue;
            bool writeByte(unsigned char byte);
            unsigned int write(unsigned char* bytes, unsigned char offset, unsigned char length);
            unsigned int write(unsigned char* bytes, unsigned char length);
    };
    You can see in UART0_UDRE_vect function that I m using txQueue.dequeue(tempByte)

    instead of txQueue.getTxQueue().dequeue(tempByte); like in my previous post
    Code:
    void UART0_UDRE_vect(void)
    {
        unsigned char* tempByte = (unsigned char*)malloc(sizeof(unsigned char));
        // Check if all data is transmitted 
        if (SerialPort::serialPortPointer->serialTransmitter.txQueue.dequeue(tempByte))
        {
            UDR1 = *tempByte;
        }
        free(tempByte);
    }
    Code:
    void UART0_UDRE_vect(void)
    {
        unsigned char* tempByte = (unsigned char*)malloc(sizeof(unsigned char));
        // Check if all data is transmitted 
        if (SerialPort::serialPortPointer->serialTransmitter.getTxQueue().dequeue(tempByte))
        {
            UDR1 = *tempByte;
        }
        free(tempByte);
    }
    My question is when I use getter and the method returns object of class CircularBuffer and since it is a private field object of Class SerialTransmitter
    I can't change it's fields even those fields (txQueue.head and txQueue.tail) of that object (CircularQueue txQueue) are public and I would need a setter for that?

    You can see that CircularBuffer's variables head and tail are public:
    Code:
    class CircularQueue
    {
        public:
            volatile unsigned char head;
            volatile unsigned char tail;
            volatile unsigned char buffer[BUFFER_SIZE];
    
    
        public:
            CircularQueue();
            bool isAvailable();
            int getAvailableElements();
            bool isEmpty();
            bool isFull(unsigned char tempTail);
            bool enqueue(unsigned char element);
            bool dequeue(unsigned char* byte);
    };
    But in a class SerialCommTransmitter (the first class in my post) txQueue is private

    Code:
    class SerialCommTransmitter : public Transmitter
    {
        private:
            CircularQueue txQueue;
            public:
                    ...
    Last edited by High Voltage; 03-04-2017 at 05:10 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C++ Interface
    By George2 in forum C++ Programming
    Replies: 8
    Last Post: 01-31-2008, 11:09 PM
  2. interface for my app
    By JordanCason in forum C++ Programming
    Replies: 2
    Last Post: 12-06-2007, 03:02 PM
  3. I/O interface
    By bean66 in forum C Programming
    Replies: 0
    Last Post: 08-28-2007, 12:53 PM
  4. What would you like in a interface?
    By commanderrulz in forum A Brief History of Cprogramming.com
    Replies: 2
    Last Post: 07-29-2002, 05:29 AM
  5. PCI ISA bus Interface
    By Mohsinzb in forum C Programming
    Replies: 0
    Last Post: 03-27-2002, 01:12 PM

Tags for this Thread