0

I have this class (full code) in Screen.h:

#include <string>
#include <iostream>

class Screen {
    using pos = std::string::size_type;
private:
    pos cursor = 0;
    pos height = 0, width = 0;
    std::string contents;
public:
    Screen() = default; // needed because Screen has another constructor

    Screen(pos ht, pos wd) : Screen(ht, wd, ' ') {}

    Screen(pos ht, pos wd, char c): height(ht), width(wd),
                                    contents(ht * wd, c) { }

    char get() const {
        return contents[cursor];
        }

    Screen& move(pos r, pos c);

    inline char get(pos ht, pos wd) const; // explicitly inline


    Screen& set(char);

    const Screen& display(std::ostream&) const;

    Screen& display(std::ostream&);

private:
        void doDisplay(std::ostream&) const;
};

and the implementation for it in Screen.cpp:

#include "Screen.h"
#include <iostream>

char Screen::get(pos r, pos c) const // declared as inline in the class
{
    pos row = r * width;      // compute row location
    return contents[row + c]; // return character at the given column
}

 inline Screen& Screen::move(pos r, pos c) {
    pos row = r * width;
    cursor = row + c;
    return *this;
}

Screen& Screen::set(char c) {
    contents[cursor] = c;
    return *this;
}

Screen& Screen::display(std::ostream& outputStream) {
    doDisplay(outputStream);
    return *this;
}

const Screen& Screen::display(std::ostream& outputStream) const {
    doDisplay(outputStream);
    return *this;
}

void Screen::doDisplay(std::ostream& outputStream) const {
    for (unsigned h = 0; h < height; ++h) {
            for (unsigned w = 0; w < width; ++w) {
                outputStream << contents[h*w];
            }
            outputStream << std::endl;
    }
}

My main file:

#include "Screen.h"
#include <iostream>

int main() {
    Screen myScreen(5, 5, 'X');
    myScreen.move(0,4).set('#').display(std::cout);
    std::cout << std::endl;

    int returnCode = EXIT_SUCCESS;
    return returnCode;
}

this produces the following linker error: undefined reference to `Screen::move(unsigned long long, unsigned long long)'

When I remove the "inline" from Screen::move, it works, but somehow the char at 0,4 doesn't get changed... I don't really know what's not working. I'm using Code::Blocks with the gcc compiler.

Edit: okay everything works fine when I remove the "inline" from the definition of the "move" method. But now my question is: why can't I specify "inline" in Screen.cpp?

Timo Türschmann
  • 4,388
  • 1
  • 22
  • 30
  • My recollection (have not worked with C++ for many years) is that you must define a "home" for the method, since "inline" is only a suggestion/permission, not an order. – Hot Licks Aug 11 '13 at 12:23
  • This basically is an exercise from the book "C++ Primer". The book tells me that it is valid to define inline outside of the class declaration. I don't know why it doesn't work for me. This is basically just a copy/paste from the book. – Timo Türschmann Aug 11 '13 at 12:26
  • Also I read this: http://www.parashift.com/c++-faq-lite/where-to-put-inline-keyword.html from this answer:http://stackoverflow.com/a/3993003/1805439 – Timo Türschmann Aug 11 '13 at 12:28
  • I'll just double check: you are linking with Screen.cpp, right? – Dave Aug 11 '13 at 12:29
  • *"..but somehow the char at 0,4 doesn't get changed... "* : You mean on your *screen* ? Or within the `Screen` code object? Significantly different concepts, so you better elaborate. – WhozCraig Aug 11 '13 at 12:31
  • Unrelated, but your display function is wrong: `outputStream << contents[h*w];` – Dave Aug 11 '13 at 12:34
  • I can't reproduce the error you're seeing, so I guess it must be something to do with your compiler / compile settings. Using inline like that should be fine, and tells the compiler to inline any calls within that compilation unit, but use the regular function outside the compilation unit. – Dave Aug 11 '13 at 12:36
  • That was a little white lie. You promised you'll inline it but then you actually didn't. – Hans Passant Aug 11 '13 at 12:38
  • oh no, wait, I can reproduce it. Now let's see if I can figure out why… – Dave Aug 11 '13 at 12:48
  • Hmm, seems I'm wrong in my views. Read point 2 here: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3538.html – Dave Aug 11 '13 at 12:52
  • Look up `#pragma hashome`/`#pragma ishome`. – Hot Licks Aug 11 '13 at 13:00

2 Answers2

0

You have inline in cpp file remove inline and it will be fine. I mean for the Screen::move function. Alternative move definition to header file.

user2672165
  • 2,986
  • 19
  • 27
  • 1
    Please read the question to the end: "When I remove the "inline" from Screen::move, it works, but somehow the char at 0,4 doesn't get changed" – Sergey Kalinichenko Aug 11 '13 at 12:22
  • Sorry I have never seen that kind of logical change due to inline vs non-inline. There is some other problem. – user2672165 Aug 11 '13 at 12:24
  • Inline normally needs to be placed in header file if to be effective in other translation units because otherwise the compiler cannot insert the whole body of the function. – user2672165 Aug 11 '13 at 12:27
  • When I think more. I can think of at least one case where you will have logical differences and that is if you use local static variables inside an inline function. Then you might end up with multiple copies of the static variable. That is not the case here. – user2672165 Aug 11 '13 at 12:45
0

Put it into *.h or make it private and use it in *cpp, exclusively.