user41638: I'm not entirely sure about the proper C++ terminology, so I'll just illustrate what I'm trying to achieve by giving a Java example since it should be pretty obvious:
public class LcdDecorator {
    private HD44780Lcd lcd;

    public LcdDecorator(int rows, int cols, int i2cAddress) {
        this.lcd = new HD44780Lcd(rows, cols, i2cAddress);
    }
}

or... alternatively...
public class LcdDecorator {
    private HD44780Lcd lcd;

    public LcdDecorator(HD44780Lcd lcd) {
        this.lcd = lcd;
    }
}

For what it's worth, there's no real concern about scope... LcdDecorator is a Singleton that gets created in setup(), then lives forever and gets used by loop() until the power gets shut off.
Here's what I've attempted so far:
LcdFacade.h:
#ifndef CORECONTROLLER_LCDFACADE_H
#define CORECONTROLLER_LCDACADE_H

#include <stdint.h>
#include "../.pio/libdeps/megaatmega2560/HD44780_LCD_PCF8574/src/HD44780_LCD_PCF8574.h"

class LcdFacade {

public:
    LcdFacade(uint8_t rows, uint8_t cols, uint8_t i2cAddress) ;
};

#endif //CORECONTROLLER_LCDFACADE_H

LcdFacade.cpp:
#include "LcdFacade.h"
#include "../.pio/libdeps/megaatmega2560/HD44780_LCD_PCF8574/src/HD44780_LCD_PCF8574.h"

HD44780LCD lcd;

LcdFacade::LcdFacade (uint8_t rows, uint8_t cols, uint8_t i2cAddress) : lcd{rows, cols, i2cAddress} {
    // ... the rest of the constructor goes here ...
}

note: I also tried using parentheses instead of braces for lcd's constructor:
LcdFacade::LcdFacade(uint8_t rows, uint8_t cols, uint8_t i2cAddress) : lcd(rows, cols, i2cAddress) {

In CLion, the 'lcd{rows, cols, i2caddress}' portion of the constructor in LcdFacade.cpp is red-underlined, and reports member initializer 'lcd' does not name a non-static data member or base class
Meanwhile, gcc(?) reports error: no matching function for call to 'HD44780LCD::HD44780LCD() on line 4 of LcdFacade.cpp.
Any ideas?

user7508: When you define
HD44780LCD lcd;

at global scope, you are creating a global variable that is initialized
before main() is called. In this case, it is initialized with the
default constructor HD44780LCD::HD44780LCD(), which does not exist,
hence the error. You could avoid this error by calling a suitable
constructor in the initialization, e.g.
HD44780LCD lcd(4, 20, 0x23);

but this may be inconvenient to you.
If you want to initialize lcd in the constructor of LcdFacade, then
it must be a non-static member of the class:
// In LcdFacade.h:
class LcdFacade {
public:
    LcdFacade(uint8_t rows, uint8_t cols, uint8_t i2cAddress);
private:
    HD44780LCD lcd;  // <- non-static member
};

// In LcdFacade.cpp:
LcdFacade::LcdFacade(uint8_t rows, uint8_t cols, uint8_t i2cAddress)
: lcd(rows, cols, i2cAddress) {
    ...
}


41638: <p>I'm not entirely sure about the proper C++ terminology, so I'll just illustrate what I'm trying to achieve by giving a Java example since it should be pretty obvious:</p>
<pre><code>public class LcdDecorator {
    private HD44780Lcd lcd;

    public LcdDecorator(int rows, int cols, int i2cAddress) {
        this.lcd = new HD44780Lcd(rows, cols, i2cAddress);
    }
}
</code></pre>
<p>or... alternatively...</p>
<pre><code>public class LcdDecorator {
    private HD44780Lcd lcd;

    public LcdDecorator(HD44780Lcd lcd) {
        this.lcd = lcd;
    }
}
</code></pre>
<p>For what it's worth, there's no real concern about scope... LcdDecorator is a Singleton that gets created in setup(), then lives forever and gets used by loop() until the power gets shut off.</p>
<h4>Here's what I've attempted so far:</h4>
<p><code>LcdFacade.h</code>:</p>
<pre><code>#ifndef CORECONTROLLER_LCDFACADE_H
#define CORECONTROLLER_LCDACADE_H

#include &lt;stdint.h&gt;
#include &quot;../.pio/libdeps/megaatmega2560/HD44780_LCD_PCF8574/src/HD44780_LCD_PCF8574.h&quot;

class LcdFacade {

public:
    LcdFacade(uint8_t rows, uint8_t cols, uint8_t i2cAddress) ;
};

#endif //CORECONTROLLER_LCDFACADE_H
</code></pre>
<p><code>LcdFacade.cpp</code>:</p>
<pre><code>#include &quot;LcdFacade.h&quot;
#include &quot;../.pio/libdeps/megaatmega2560/HD44780_LCD_PCF8574/src/HD44780_LCD_PCF8574.h&quot;

HD44780LCD lcd;

LcdFacade::LcdFacade (uint8_t rows, uint8_t cols, uint8_t i2cAddress) : lcd{rows, cols, i2cAddress} {
    // ... the rest of the constructor goes here ...
}
</code></pre>
<p>note: I also tried using parentheses instead of braces for lcd's constructor:</p>
<pre><code>LcdFacade::LcdFacade(uint8_t rows, uint8_t cols, uint8_t i2cAddress) : lcd(rows, cols, i2cAddress) {
</code></pre>
<p>In CLion, the 'lcd{rows, cols, i2caddress}' portion of the constructor in LcdFacade.cpp is red-underlined, and reports <code>member initializer 'lcd' does not name a non-static data member or base class</code></p>
<p>Meanwhile, gcc(?) reports <code>error: no matching function for call to 'HD44780LCD::HD44780LCD()</code> on line 4 of LcdFacade.cpp.</p>
<p>Any ideas?</p>
 7508: <p>When you define</p>
<pre class="lang-cpp prettyprint-override"><code>HD44780LCD lcd;
</code></pre>
<p>at global scope, you are creating a global variable that is initialized
before <code>main()</code> is called. In this case, it is initialized with the
default constructor <code>HD44780LCD::HD44780LCD()</code>, which does not exist,
hence the error. You could avoid this error by calling a suitable
constructor in the initialization, e.g.</p>
<pre class="lang-cpp prettyprint-override"><code>HD44780LCD lcd(4, 20, 0x23);
</code></pre>
<p>but this may be inconvenient to you.</p>
<p>If you want to initialize <code>lcd</code> in the constructor of <code>LcdFacade</code>, then
it must be a non-static member of the class:</p>
<pre class="lang-cpp prettyprint-override"><code>// In LcdFacade.h:
class LcdFacade {
public:
    LcdFacade(uint8_t rows, uint8_t cols, uint8_t i2cAddress);
private:
    HD44780LCD lcd;  // &lt;- non-static member
};

// In LcdFacade.cpp:
LcdFacade::LcdFacade(uint8_t rows, uint8_t cols, uint8_t i2cAddress)
: lcd(rows, cols, i2cAddress) {
    ...
}
</code></pre>
