Return correct subclass instance, identified by string
Use all the power of the standard library
In your post on StackOverflow, you mentioned that you couldn't use std::map because you were not allowed to use it. Outside of the classroom, you should not limit yourself this way, and instead use the appropriate functions from the standard library that help you write concise and efficient code. The function func() could look like:
Form *func(std::string_view name)
{
    static const std::unordered_map&lt;std::string_view, std::function&lt;Form*()&gt;&gt; forms = {
        {&quot;triangle&quot;,  []{return new Triangle;}},
        {&quot;rectangle&quot;, []{return new Rectangle;}},
        ...
    };

    if (auto found = forms.find(name); found != forms.end()) {
        return found-&gt;second();
    } else {
        return nullptr;
    }
}

And instead of raw pointers, you should probably return std::unique_ptr&lt;Form&gt;.
In the rest of the review I'm going to assume you are limited to what you can use.
Prefer using = default
It's usually best to let the compiler generate default constructors, destructors and other operators. In some cases, you have to explicitly tell it to add one of those, for example when you want to ensure the destructor of Form is virtual. In that case, use = default instead of {}:
class Form
{
public:
    virtual ~Form() = default;
};

Use \n instead of std::endl
Prefer using \n instead of std::endl, the latter is equivalent to the former but also forces a flush of the output, which might be bad for performance if you are printing a lot.
Avoid unnnecessary parentheses and void
You can simplify the createForm() functions a bit:
static Form *createForm()
{
    return new Square;
}

The unnecessary parentheses and void in the argument list are just unnecessary distractions here.
Move s_makeForms into func()
You can move the definition of struct s_makeForm into func(), so it doesn't clutter the global namespace. In fact, you don't even have to give this struct a name, you can write:
Form *func(std::string &amp;name)
{
    struct {
        std::string name;
        Form *(*createForm)();
    } forms[] = {
        &quot;triangle&quot;, Triangle::createForm},
        ...
    }

    ...
}

Prefer const std::string &amp; when passing string arguments
To avoid unnecessary copying of strings, prefer passing strings as const references:
Form *func(const std::string &amp;name)
{
    ...
}

Avoid having to #define NB_FORMS
You can get the size of the array allForms in various ways, the typical trick that works both in C and all versions of C++ is:
struct ... allForms[] = {...};
size_t numForms = sizeof allForms / sizeof *allForms;

for (size_t i = 0; i &lt; numForms; ++i)
{
    ...
}

You can also use a range-based for-loop to iterate over the array:
struct ... allForms[] = {...};

for (auto &amp;form: allForms)
{
    if (name == form.formName)
        return form.makeForm();
}

Memory leak
There is a memory leak in your program, since you forgot to call delete myform. These kinds of errors can be avoided by using smart pointers, such as std::unique_ptr.