Vehicle.cpp compiles without error. vehicle-test.cpp does not compile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
./vehicle-test.cpp: In function ‘int main()’:
./vehicle-test.cpp:8:10: error: no matching function for call to ‘Vehicle::Vehicle()’
Vehicle jaguar;
^
./vehicle-test.cpp:8:10: note: candidates are:
In file included from ./vehicle-test.cpp:2:0:
./Vehicle.h:11:2: note: Vehicle::Vehicle(int, int)
Vehicle(int wheels, int doors) {}
^
./Vehicle.h:11:2: note: candidate expects 2 arguments, 0 provided
./Vehicle.h:4:7: note: Vehicle::Vehicle(const Vehicle&)
class Vehicle
^
./Vehicle.h:4:7: note: candidate expects 1 argument, 0 provided
./vehicle-test.cpp:15:2: error: ‘jaguar’ is not a class or namespace
jaguar::printNumWheels();
^
My question is - with function overloading, why does the compiler complain that there is no matching function? The C++ tutorial I am reading on the subject of constructors ( http://www.learncpp.com/cpp-tutorial/85-constructors/ ) explains that I should be able to do this?
{
#include <iostream>
#include "Vehicle.h"
usingnamespace std;
int main()
{
Vehicle jaguar;
jaguar.setNumWheels(4);
// cout << "Jaguar has " << jaguar.getNumWheels() << " wheels and ";
// cout << 4 << " doors" << endl;
jaguar.printNumWheels(); //Line 16 of vehicle-test.cpp, you can't use ::(scope resolution operator), you have to use .(dot, member access operator) since it isn't a static member function
return 0;
}
}
Note: You may have more than one constructor as long as the parameters are different,so that when a call enters an object scope, it will know which constructor to execute. This is overloadding, not just having a single constructor.
Thanks for that. That is how I have always understood constructor overloading. I deliberately did not create a constructor that takes no arguments, as according to the instructions on the constructor tutorial (see original post), my code should have worked? According to that web page, I can have a single constructor that adapts its behaviour accordingly, therefore doing away with the traditional overloading.
When I tried to copy that constructor as shown in the examples, my code fails.
The code compiles, but produces no output. So there are the two issues which I am trying to resolve: 1) Why I was not able to get the constructor to work as defined in the tutorial page, and 2) why Vehicle::printNumWheels() is generating no output.
Which reminds me: Why are you defining the class twice? Why don't you just define the class in the header file and then implement it in the source file? That means that if you change the layout of your class you only need to modify it once, rather than twice, which can help prevent bugs (like this one).
why Vehicle::printNumWheels() is generating no output.
You now have two different definitions of your Vehicle class - one in Vehicle.h, and one in Vehicle.cpp. vehicle-test.cpp includes Vehicle.h, so uses the definition of the class supplied in Vehicle.h.
Have a look at the way you've defined Vehicle::printNumWheels() in Vehicle.h. What would you expect it to print out?
EDIT: I'm surprised your compiler isn't giving you an error about the Vehicle class being defined twice. Are you linking Vehicle.cpp into your build?
Oh, I didn't realise that I was technically defining the class twice. I agree, it should be defined in the header and then implemented in the source. Is that not what I have done? I'm just starting off here so I'm trying to understand best practice, but I feel a bit confused now.
So if I make Vehicle.h define the constructor as
Vehicle(int wheels = 4; int doors = 4);
Does this then allow me to use the behaviour as shown in the tutorial, and instantiate a Vehicle with 0,1, or 2 arguments?
Have a look at the way you've defined Vehicle::printNumWheels() in Vehicle.h. What would you expect it to print out?
I'm not sure I understand. Vehicle.h defines the method printNumWheels as having a void return type, which is correct, as it does not return anything. Where I have implemented the method in Vehicle.cpp it prints out to the console the number of wheels that a particular car has ?
Now that we have cleared up the fact that I was implementing functions within the header, I am trying to work out how to get that arrangement with a single constructor that can take multiple numbers of parameters can work, as shown in the tutorial page.
Can anyone suggest how this Vehicle code should be arranged to allow that?
Ah I see, thanks. So when declaring a function in the header file, leave off the curly braces!
In the header file, you can either:
1) Define the function, giving the complete code for the function's implementation. you do this, you use the curly braces.
OR:
2) Declare the function, giving just the name, the types of the arguments, and the return type. If you do this, you don't use the curly braces, and you need to put the definition in a .cpp file.
$ g++ ./Vehicle.o ./vehicle-test.o -o test
./vehicle-test.o: In function `main':
vehicle-test.cpp:(.text+0x79): undefined reference to `Vehicle::Vehicle()'
vehicle-test.cpp:(.text+0x87): undefined reference to `Vehicle::setNumWheels(int)'
vehicle-test.cpp:(.text+0x90): undefined reference to `Vehicle::printNumWheels()'
collect2: ld returned 1 exit status
I'm not sure why it is unable to find those references.
vehicle-test.cpp:
1 2 3 4 5 6 7 8 9 10 11
#include <iostream>
#include "Vehicle.h"
usingnamespace std;
int main ()
{
Vehicle jaguar;
jaguar.setNumWheels(4);
jaguar.printNumWheels();
}
Vehicle.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#ifndef __VEHICLE_INCLUDED__
#define __VEHICLE_INCLUDED__
class vehicle
{
int numWheels;
int numDoors;
public:
Vehicle();
void setNumWheels(int wheels);
void setNumDoors(int doors);
int getNumWheels();
int getNumDoors();
void printNumWheels();
};
#endif
You still have two class definitions for Vehicle. The following block:
1 2 3 4
class Vehicle
{
// Stuff
};
is a class definition. You're defining a class called Vehicle in Vehicle.h, and another class also called Vehicle in Vehicle.cpp.
The one in the header doesn't contain definitions for the methods, just declarations. Presumably that's the one the linker is trying to use, hence the link errors.
Is your compiler not warning you about the double definition of the class? If not, are you absolutely sure you're linking Vehicle.cpp into your program?
EDIT: As ne555 spotted below, you're not actually defining the same class twice - you're defining a class called vehicle, and one called Vehicle.