C++ Inheritance: Calling constructor w/ args - c++

I'm trying to invoke my parent class's constructor that has arguments, in my child class's constructor with arguments, but I get a compiler error "expected primary expression before ...".
This is what I have:
class Ship {
private:
string shipName;
int yearBuilt;
public:
Ship();
Ship(string name, int year);
};
class CruiseShip: public Ship {
private:
int maxPeople;
public:
CruiseShip()
: Ship() {
maxPeople = 100;
}
CruiseShip(int m)
: Ship(string name, int year) {
maxPeople = m;
}
};
Ship::Ship() {
shipName = "Generic";
yearBuilt = 1900;
}
Ship::Ship(string name, int year) {
shipName = name;
yearBuilt = year;
}
And this is the specific piece of code I'm having trouble with:
CruiseShip(int m)
: Ship(string name, int year) {
maxPeople = m;
}
My goal is to be able to create an object, CruiseShip c1 with 3 arguments that set the name,year, & max people.
I've been reading online and it tells me that this should be ok, but I'm obviously doing something wrong. I'd appreciate any input, thanks!

You need to pass parameters to parent class constructor like this:
CruiseShip(int m, string name, int year): Ship(name, year), maxPeople(m) {}
Better, you should set maxPeople to m in the initializer list.

Related

C++ Null output when a function is called

Below is a snippet of code from my main program
My H file
class Person{
public:
std::string name;
int rangeStance;
int initialStance;
Person(std::string name, int rangeStance, int initialStance){
name = name;
rangeStance = rangeStance;
initialStance = initialStance;
setName(getName());
setRangestance(getRangeStance());
setinitalStance(getRangeStance());
}
Person();
void setName(std::string name);
void setRangestance(int range);
void setinitalStance(int stance);
std::string getName();
int getRangeStance();
int getinitalStance();
double impact(int rangeStance, int initalStance);
};
class Leader: public Person {
public:
int popularity;
int totalcountryVotes;
Leader(std::string name, int rangeStance, int initialStance,int popularity, int totalcountryVotes)
:Person(name, rangeStance, initialStance), popularity(popularity), totalcountryVotes(totalcountryVotes){
popularity = popularity;
totalcountryVotes = totalcountryVotes;
setPopularity(getPopularity());
setTotalcountryVotes(getTotalcountryVotes());
}
Leader();
void setPopularity(int popularity);
void setTotalcountryVotes(int totalcountryVotes);
int getPopularity();
int getTotalcountryVotes();
};
The corresponding functions in the main cpp file.
Person::Person() {
}
void Person::setName(string Name)
{
name = Name;
}
string Person::getName() {
return name;
}
void Person::setRangestance(int Range)
{
rangeStance = Range;
}
int Person::getRangeStance() {
return rangeStance;
}
void Person::setinitalStance(int stance)
{
initialStance = stance;
}
int Person::getinitalStance() {
return initialStance;
}
Leader::Leader() {
}
void Leader::setPopularity(int popularity) {
popularity = popularity;
}
void Leader::setTotalcountryVotes(int totalcountryVotes) {
totalcountryVotes = totalcountryVotes;
}
int Leader::getPopularity() {
return popularity;
}
int Leader::getTotalcountryVotes() {
return totalcountryVotes;
}
Within main the needed funtions are called appropriately
int main(int argc, char* argv[]) {
Leader labourLeader("George Lopez",100,50,50, 75);//sets record for the labour party leader
cout << "--Party Leader--" << endl;
cout << labourLeader.getName() << endl;
return 0;
}
However when this snippet of code is compiled, no outcome is returned where it should be printing out "George Lopez". Im fairly "noob" with c++, am i using my contructor right or should I be delcaring it within my h file? Thankyou.
A couple of things wrong in this code
Person(std::string name, int rangeStance, int initialStance){
name = name;
rangeStance = rangeStance;
initialStance = initialStance;
setName(getName());
setRangestance(getRangeStance());
setinitalStance(getRangeStance());
}
Firstly it's not necessary to call setters and to do assignments, so lets drop those, leaving
Person(std::string name, int rangeStance, int initialStance){
name = name;
rangeStance = rangeStance;
initialStance = initialStance;
}
Now think about what name = name does. Does that look curious to you at all? It takes the parameter name and assigns it to the parameter name! The member variable also called name is completely unchanged. This situation where one name hides another similar name is called shadowing.
Person(std::string name, int rangeStance, int initialStance) {
name = name;
What's happening there is that it's just overwriting the parameter with itself, rather than copying it to the member variable. That's because the name lookup rules for unqualified names at that point prefer the parameter to the member variable. That means the member variable is being left at its constructed state, an empty string.
There are a few ways to fix this. The first is to simply name them differently so that there's no ambiguity, such as the common method of prefixing member variables with m_. That way, the statement becomes the more explicit:
m_name = name;
Another alternative is to be explicit about the one you're assigning to so that it's no longer unqualified:
this->name = name;
A third is to use initialiser lists where the rules are slightly different in that it uses the member variable outside the parentheses and does normal unqualified lookup within the parentheses:
Person(std::string name, int rangeStance, int initialStance)
: name(name)
, rangeStance(rangeStance)
, initialStance(initialStance)
// ^ ^
// | |
// | +- normal lookup, passed-in parameter.
// +--------------- member variable.
{
};
And there's no need to have all those other statements in the constructor, such as setName(getName()), since you've already set the name.

How to fix an "no instance of constructor matches argument list" error in C++?

I am learning C++ right now and I am writing a program that utilizes member initializer list. Here is the code that I am working with:
#include <cstdio>
struct ClockOfTheLongNow {
ClockOfTheLongNow() {
year = 2019;
}
void add_year() {
year++;
}
bool set_year(int new_year) {
if (new_year < 2019) return false;
year = new_year;
return true;
}
int get_year() const {
return year;
}
private:
int year;
};
struct Avout{
Avout(const char* name, long year_of_apert) : name{ name }, apert{ year_of_apert } {
}
void announce() const {
printf("My name is %s and my next apert is %d.\n", name, apert.get_year());
}
const char* name;
ClockOfTheLongNow apert;
};
int main() {
Avout raz{ "Eramas", 3010 };
Avout jad{ "Jad", 4000 };
raz.announce();
jad.announce();
}
The error that I am getting is coming from this line here where it says apert{ year_of_apert }:
Avout(const char* name, long year_of_apert) : name{ name }, apert{ year_of_apert } {
The error that I am getting back is this:
no instance of constructor "ClockOfTheLongNow::ClockOfTheLongNow" matches the argument list -- argument types are: (long)
I have already tried to look up solutions to the problem but, so far, have had no luck. The expected output is supposed to be this:
My name is Erasmas and my next apert is 3010.
My name is Jad and my next apert is 4000.
ClockOfTheLongNow does not have a constructor that takes a long (or any other kind of value) as input, but you are trying to construct the apert member by passing year_of_apert to its constructor.
You need to add a converting constructor to ClockOfTheLongNow, eg:
struct ClockOfTheLongNow {
ClockOfTheLongNow() { // <-- default constructor
year = 2019;
}
ClockOfTheLongNow(int theYear) { // <-- add a converting constructor
year = theYear;
}
...
private:
int year;
};
Alternatively, you can change your existing default constructor to give it a default parameter value so it can act as a converting constructor as well, eg:
struct ClockOfTheLongNow {
ClockOfTheLongNow(int theYear = 2019) { // <-- default + converting constructor
year = theYear;
}
...
private:
int year;
};
The error is telling you there is no constructor present for the type you are giving it in the parameters.
You give a type long parameter to the Avout constructor, which you then initialize in the apert variable, which is of the type ClockOfTheLongNow.
In other words, you have to create a new constructor for your clock struct which would look something like this:
ClockOfTheLongNow(long parameterYear) {
year = parameterYear;
}

Call constructor with different argument types from another constructor in C++17

I have a class called Date:
class Date {
public:
explicit Date(const int day = 1, const int month = 1, const int year = 0) {
this->Construct(day, month, year);
}
explicit Date(const string &date_as_string) {
int day, month, year;
// parsing the string date_as_string
this->Construct(day, month, year);
}
private:
void Construct(const int day, const int month, const int year) {
// constructing the Date object
}
};
Is there a way to call Date(int, int, int) directly from Date(string&), thus avoiding writing a separate function?
UPD:
Some clarification. My class should look like:
class Date {
public:
explicit Date(const int day = 1, const int month = 1, const int year = 0) {
// constructing the Date object
}
explicit Date(const string &date_as_string) {
int day, month, year;
// parsing the string date_as_string
// call Date(day, month, year) to construct the Date object
}
// any other functions
private:
// private fields
};
And the following code should compile:
Date date("some_string_containing_date");
Date date(1, 1, 0);
Yes, you can define one constructor in terms of another. No, I don't think you can do it without some additional function.
A constructor which invokes another constructor of the same class is called a "delegating constructor", and uses the same sort of syntax as a member initializer list, but using the class's own name instead of its base classes and members:
ClassName::ClassName(SomeParam1 p1, SomeParam2 p2)
: ClassName(arg_expr1, arg_expr2, arg_expr3)
{ /* any other logic after the target constructor finishes */ }
But this case is a bit tricky because of the need for the intermediate object date_as_struct. Or with the updated question, just the need to do some parsing before entering another constructor. I'd solve this one by making an additional private constructor which takes the Date_as_struct:
class Date {
public:
explicit Date(int day = 1, int month = 1, int year = 0);
explicit Date(const string &date_as_string);
/* ... */
private:
struct Date_as_struct {
int day;
int month;
int year;
};
explicit Date(const Date_as_struct&);
static Date_as_struct ParseStringContainingDate(const std::string&);
};
Date_as_struct and ParseStringContainingDate are declared here as private, since it sounds like nothing else will really use them.
Then for the string constructor, you just have
Date::Date(const std::string& date_as_string)
: Date(ParseStringContainingDate(date_as_string))
{}
The Date(const Date_as_struct&) constructor can very easily delegate to Date(int, int, int) or vice versa, whichever is more natural for the actual member initialization.

Constructor for a class within a class

I have 2 classes, Date and Employee.
//Date
class Date
{
private:
int dd;
int mm;
int yy;
public:
Date (int, int, int);
void setDate (int, int, int);
int getDD();
int getMM();
int getYY();
};
//Employee
class Employee
{
private:
int ID;
string qualification;
double salary;
Date DOB;
Date dateJoined;
public:
Employee();
void setEmployee (int, string, double, Date, Date);
Date getDOB();
Date getDateJoined();
string getQualification();
void displayEmployee();
};
This is my constructor for Employee class.
Employee::Employee()
{
ID = 0;
qualification =" " ;
salary=0.0;
Date DOB();
Date dateJoined();
}
I got error C2512: 'Date' : no appropriate default constructor available.
How do I initialize DOB and dateJoined inside the Employee class?
The issue is that before the Employee constructor body is entered, all of the data members are constructed. In this instance, DOB and dateJoined need to be default-initialized, but there is no default constructor for your Date class. Your two main options are to add a default constructor for Date, or to initialize those members in the Employee constructor initializer list.
Option 1:
class Date
{
Date (); //define this somewhere
};
Option 2:
Employee::Employee() :
ID(0),
qualification(" "),
salary(0.0),
DOB(/*some data, maybe taken in as constructor args*/),
dateJoined(/*ditto*/)
{ }
Try this modification. You need a constructor Date():
class Date
{
private:
int dd;
int mm;
int yy;
public:
Date () {return;}
Date (int, int, int);
void setDate (int, int, int);
int getDD();
int getMM();
int getYY();
};
Another solution is:
Employee::Employee():
DOB(0,0,0),
dateJoined(0,0,0)
{
ID = 0;
qualification =" " ;
salary=0.0;
}

Base class is undefined error (C2504)

I'm just starting out with OOP in C++ and I keep getting "base class undefined error". I'm coding a project that is basically a Library, but using classes. Google hasn't really been helping much because it seems that most of the time the error happened for other people was circular references in writing their own headers.
Here is the program(excuse the lengthiness, I crammed everything into one file for the time being)
driverLibrary.cpp:
#include "stdafx.h"
#include <iostream>
using namespace std;
class LibraryItem :public Borrowable{
public:
LibraryItem(string name, int id) :identifier(name), id(id){}
LibraryItem();
~LibraryItem();
string getIdentifier(){
return identifier;
}
int getId(){
return id;
}
bool borrow(){ return false; }
bool canBorrow() { return false; }
bool operator== (LibraryItem &comparison)
{
return (comparison.getId() == this->id);
}
protected:
string identifier;
int id;
};
class Borrowable{//interface
public:
bool isIn;
virtual bool borrow() = 0;
virtual bool canBorrow() = 0;
};
class Book :public LibraryItem, public Borrowable{ //all children will be borrowed the same way unless specified in their own class
public:
Book(string name, int id, string author, string genre) :author(author), genre(genre){ LibraryItem(name, id); }
Book(string name, int id, string author){ LibraryItem(name, id); this->author = author; }
string getAuthor(){ return author; }
string getGenre(){ return genre; }
//override
bool borrow(){
if (!isIn) return false;
else isIn = false;
return true;
}
bool canBorrow(){ return isIn; }
protected:
string author;
string genre;
bool isIn;//override
};
class Newspaper : public Media{
public:
Newspaper(string name, int id, int vol, int issue) : vol(vol), issue(issue){ LibraryItem(name, id); }
int getVol(){ return vol; }
int getIssue(){ return issue; }
bool borrow(){
if (!isIn) return false;
else isIn = false;
return true;
}
bool canBorrow(){ return isIn; }
protected:
int vol;
int issue;
bool isIn;
};
class Reference : public Book{//, public Borrowable{
public:
Reference(string name, int id, string author, int vol, int issue, string topic) : vol(vol), issue(issue), topic(topic), Book(name, id, author){}
int getVol(){ return vol; }
int getIssue(){ return issue; }
// bool borrow(){ return false; }
// bool canBorrow(){ return false; }
protected:
int vol;
int issue;
string topic;
};
class Magazine : public Media, public Borrowable{
public:
Magazine(string name, int id, string title, string publisher, int date);
};
class Media : public LibraryItem, public Borrowable{
public:
Media(string name, int id, string title, string publisher) : title(title), publisher(publisher), LibraryItem(name, id){}
bool borrow(){
if (!isIn) return false;
else isIn = false;
return true;
}
bool canBorrow(){ return isIn; }
protected:
string title;
string publisher;
bool isIn;
};
class CD :public Media{
public:
CD(string name, int id, string title, string publisher, int length, string artist) :length(length), artist(artist), Media(name, id, title, publisher) {}
int getLength(){ return length; }
string getArtist(){ return artist; }
protected:
int length;
string artist;
};
class DVD : public Media{
public:
DVD(string name, int id, string title, string publisher, int dpi) : dpi(dpi), Media(name, id, title, publisher) {}
int getDPI(){ return dpi; }
protected:
int dpi;
};
int main()
{
Book book = Book("Identifier", 234, "Mike Hunt");
return 0;
}
And here is the error log:
Error 1 error C2504: 'Borrowable' : base class undefined c:\users\connor\documents\visual studio 2013\projects\consoleapplication2\consoleapplication2\driverlibrary.cpp 8 1 ConsoleApplication2
Error 2 error C2504: 'Media' : base class undefined c:\users\connor\documents\visual studio 2013\projects\consoleapplication2\consoleapplication2\driverlibrary.cpp 53 1 ConsoleApplication2
Error 3 error C2504: 'Media' : base class undefined c:\users\connor\documents\visual studio 2013\projects\consoleapplication2\consoleapplication2\driverlibrary.cpp 81 1 ConsoleApplication2
4 IntelliSense: no default constructor exists for class "Media" c:\Users\Connor\Documents\Visual Studio 2013\Projects\ConsoleApplication2\ConsoleApplication2\driverLibrary.cpp 55 77 ConsoleApplication2
You need to declare (and in some cases, define) classes before they are used. This is just like variables, functions, and anything else in C++.
You should be able to fix the first three errors that the compiler is reporting by moving the definition of Borrowable to the top of your file and putting Media right after LibraryItem.
The fourth error is because Newspaper doesn't explicitly call a constructor for Media, and Media has no default constructor that the compiler can insert a call to.
C++ type's visibility extend from the point they are first declared forward. Order matters, it is an inherited trait of the C language, based on "textual" treatment of include files as opposed to true modules or multi file type metadata, where the compiler traditionally notes each type as it is declared syntactically, stores it in a symbol table, where it is immediately available.
This differs from Java or C# compilers which parse the whole source file first, then resolve types and symbols later, removing order from the equation.
To allow cyclical relationships in C++ there is a feature called a forward declaration. It allows you to declare pointer types to a type that hasn't yet been defined (note declared is different from defined).
class A; // declaration
class B {
class A * a; // refers to A, but does not use any members within A yet
};
class A { // definition
int size;
};