5

I have a class B that creates an object of a class A and calls a method of the object.

a.h

#ifndef A_H
#define A_H

class A
{
public:
    A(int);
    void function();
};

#endif // A_H

a.cpp

#include "a.h"

A::A(int x)
{

}
void A::function(){
    //Do something.
}

b.h

#ifndef B_H
#define B_H
#include <QVector>
#include <a.h>


class B
{
public:
    B(int);
    QVector<A> list;
};

#endif // B_H

b.cpp

#include "b.h"

B::B(int y)
{
    list.append(A(y));
    list[0].function();
}  

The problem is that this does not compile. It returns "no matching function to call 'A:A()'". I know that this can be solved with a forward declaration but this does not work here since I want to call the function "function". I also do not want to include the whole class A in the class B.

Luca9984
  • 141
  • 6

2 Answers2

11

As with many Qt containers, QVector's element type must be an assignable data type in your version.

Unlike the standard library, Qt defines this as:

The values stored in the various containers can be of any assignable data type. To qualify, a type must provide a default constructor, a copy constructor, and an assignment operator.

This is really unfortunate, because there's no practical need for a default constructor in your example, and indeed a std::vector would (compliantly) let you use an element type that doesn't have one.

The QVector::value(int) function does rely on this property, but you're not using it! The Qt devs must be doing some kind of checks up-front, rather than taking the standard library's approach of "just check preconditions when they're actually needed", or else this is an "accident" of the code!

As a consequence, until 5.13 in which this was changed, you will have to give A a default constructor, sorry.

Don't forget a copy constructor, too… and a proper qualification on that A::function() definition.

A forward declaration will not solve this, neither do you need one. In fact, adding one to this particular program will do literally nothing. ;)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 2
    The alternative solution is to switch to `std::vector` of course. – Martin Bonner supports Monica Jan 14 '19 at 12:38
  • 1
    Good News Everyone! The requirement of a default constructor for QVector has been finally dropped in 5.13 ([commit](https://code.qt.io/cgit/qt/qtbase.git/commit/?id=01301b0b340df736dd1b0a54b3026e00b49c5ea3)). – peppe Jan 14 '19 at 14:13
  • *The Qt devs must be doing some kind of checks up-front, rather than taking the standard library's approach of "just check preconditions when they're actually needed".* It's worse... it's just sloppy coding, e.g. calling `resize()` from insertion functions or stuff like that :-( – peppe Jan 14 '19 at 14:14
  • @peppe: Possibly. Possibly not. (Ignore if you literally know otherwise from the source!) – Lightness Races in Orbit Jan 14 '19 at 14:39
  • Gory details: in 5.12 `detach()` (called by any non-const function, e.g. insertion functions) calls into `reallocData()`, which is a one-size-fits-all function that does detaching, allocation, resizing, reserving, and so on. The result is the imposed requirement. Other functions are also sloppy coded (e.g. `clear()` in 5.12 calls `resize(0)`). – peppe Jan 14 '19 at 14:53
0

First in a.cpp update function definition:

void A::function(){  // A: added
    //Do something.
}

Second, I would add A(const A&) copy constructor since list may need this for internal buffer reallocation purposes.

grapes
  • 8,185
  • 1
  • 19
  • 31
  • 2
    While you're right that the `function` definition is currently broken, and that a copy constructor should be added, none of this answers the question, which is about why a default-constructor is being invoked and how best to resolve that. – Lightness Races in Orbit Jan 14 '19 at 12:15