Assuming I am making a library of books in C++ this way:
#include <iostream>
#include <string>
#include <vector>
class Book
{
public:
Book(string name, string author)
};
Simple, just a constructor, now I create a vector of Book and push books back:
int main()
{
vector<Book> books;
books.push_back(Book("Gatsby", "Fitzgerald"));
But when I try to print out some member (name or author):
cout << books[0].name << endl;
return 0;
}
My boy compiler is angry:
error: ‘__gnu_cxx::__alloc_traits >::value_type {aka class Book}’ has no member named ‘name’
cout << books[0].name << endl;
I'm a relative beginner, does this approach make sense at all? And if it does, what did I do wrong?
Thank you!
The class Book has no members to store name and author. And, the constructor that you defined is syntactically wrong.
With public data members, it would look like this:
class Book
{
public:
// data members
std::string name;
std::string author;
// parameterized constructor
Book( std::string name, std::string author )
{
this->name = name;
this->author = author;
}
};
Please note that:
exposing data members like that is in violation of data-hiding principle of OOP. Ideally, the data members should be private and adequate accessor methods should be used.
the assignments of name and author in the body of the constructor is just for your understanding. If you've already studied the initializer list for constructor then use that.
Here's an example (live):
#include <iostream>
#include <string>
#include <vector>
class Book final
{
public:
// constructor with initializer list
Book( std::string name_, std::string author_ ) : name{name_}, author{author_} {}
// accessor methods
std::string getName() const { return name; }
std::string getAuthor() const { return author; }
private:
std::string name;
std::string author;
};
int main()
{
std::vector<Book> books;
books.push_back( Book{"The Alchemist", "Paulo Coehlo"} );
books.push_back( Book{"Fight Club", "Chuck Palahniuk"} );
books.push_back( Book{"No Country for Old Men", "Cormac McCarthy"} );
books.emplace_back( "Brave New World", "Aldous Huxley" );
books.emplace_back( "1984", "George Orwell" );
books.emplace_back( "Animal Farm", "George Orwell" );
for ( const auto& book : books )
{
std::cout << book.getName() << " by " << book.getAuthor() << '\n';
}
return 0;
}
Some relevant threads to read:
Why is "using namespace std;" considered bad practice?
push_back vs emplace_back
range-for loop
C++: "std::endl" vs "\n"
Related
I'm fairly new to C++ and I've been working on an assignment where I'm tasked with displaying given social media posts with classes and objects. I was doing okay but I keep getting this error that says No instance of constructor "Post::Post" matches argument list. I think I'm missing something simple and I was hoping someone could point out to me.`
Main.cpp
#include <iostream>
#include "Post.hpp"
#include <string>
int main() {
Post post1("Chicken came before the egg confirmed!", "A new story just released where we finally get the answer of who came first."); //error appears on this line
std::cout << post1.getTitle() << std::endl;
std::cout << post1.getBody() << std::endl;
post1.getTimeStamp();
post1.setTitle("Actually the egg came first!");
post1.setBody("Ok, maybe the decision is not final.");
std::cout << std::endl;
post1.displayPost();
Post.hpp
#ifndef POST_HPP
#define POST_HPP
#include <string>
#include <ctime>
class Post {
private:
std::string Title;
std::string Body;
time_t Time;
public:
void setTitle(string title);
string getTitle();
void setBody(string body);
string getBody();
void setTimeStamp();
int getTimeStamp();
void displayPost();
}
#endif
Post.cpp
#include "Post.hpp"
#include <string>
class Post {
private:
string Title;
string Body;
time_t Time;
public:
void setTitle(string title){
Title = title;
}
string getTitle(){
return Title;
}
void setBody(string body){
Body = body;
}
string getBody(){
return Body;
}
void setTimeStamp(int time){
Time = time;
}
void getTimeStamp(){
struct tm *timestamp;
time_t ltime;
time(<ime);
timestamp = localtime(<ime);
printf("Today is %s",
asctime(timestamp));
}
void displayPost(){
cout << Title << Time << " :" << Body <<endl;
}
};
You need to add constructor to your code that takes two string parameters in your post.hpp file, something like:
public:
Post(const std::string &s1, const std::string &s2);
You forgot to code a custom constructor of your class Code. It goes like this:
class Post {
public:
Post(string title, string body) : Title(title), Body(body){} // It creates an instance of the class Post
// Add member functions and variables below
I am trying to create a class object s2 with some customized attributes and some attributes from default constructor however my output is the wrong output for the get_year function. It should be outputing 0 which is the key for FRESHMAN but it is out putting 2 instead. The rest of the code is outputting as expected:
#include <stdio.h>
#include <iostream>
#include <algorithm> // for std::find
#include <iterator> // for std::begin, std::end
#include <ctime>
#include <vector>
#include <cctype>
using namespace std;
enum year {FRESHMAN, SOPHOMORE, JUNIOR, SENIOR};
struct name
{
string firstName;
string lastName;
friend std::ostream& operator <<(ostream& os, const name& input)
{
os << input.firstName << ' ' << input.lastName << '\n';
return os;
}
};
class Student: name{
private:
name Name;
year Year;
int idNumber;
string Department;
public:
void setname(string fn="", string ln="")
{
Name.firstName =fn;
Name.lastName =ln;
}
name get_name()
{
return Name;
}
void set_year(year yr=FRESHMAN)
{
Year=yr;
}
year get_year()
{
return Year;
}
void set_ID(int ID=0)
{
idNumber=ID;
}
int get_ID()
{
return idNumber;
}
void set_Department(string Dept="")
{
Department=Dept;
}
string get_Department()
{
return Department;
}
};
int main()
{
Student s2;
s2.setname("Nikolai", "Khabeboolin");
s2.set_ID(12436193);
cout<<"ID is: "<< s2.get_ID()<<", name is "<< s2.get_name()<<", year in school is: "<<s2.get_year()<<", Department is "<<s2.get_Department()<<endl;
return 0;
}
Student lacks a constructor, so all its members are default initialized, and the default initialization of year Year and int idNumber is "no initialization", so reading from them is undefined behavior. Reading them might find 0, 2, a random value each time, or crash.
I see that your class contains a void set_year(year yr=FRESHMAN) member, but your code never called set_year, so no part of this executed.
You should make a default constructor for Student, or as Goswin von Brederlow stated, use year Year{FRESHMAN}; and int idNumber{-1}; when declaring the members, to give them default initializations.
By not explicitly declaring and defining a constructor, in this case Student(), you open yourself up to undefined behavior. Your constructor should call set_year(year yr=FRESHMAN) OR even better, just set the year itself.
I am trying to create a simple program in C++ that creates lists of movies using 2 classes: Movie, which contains details of one movie, and Movies, which contains a name and a vector of Movie objects. The whole point is that the user should only interact with the class Movies, therefore I have chosen to make all the members (both data and methods) of the Movie class private.
I keep getting the following error if I let Movie::~Movie() as it is, but if I comment it in both .h and .cpp, it works just fine.
I have explicitly made Movies class a friend of Movie class, so it can access all its members.
error from Visual Studio Community 2019
Movie.h:
#pragma once
#include<iostream>
#include<string>
class Movie
{
friend class Movies;
private:
std::string name;
std::string rating;
int watchedCounter;
int userRating;
std::string userOpinion;
// methods also private because the user should only interact with the Movies class, which is a friend of class Movie
std::string get_name() const;
Movie(std::string nameVal = "Default Name", std::string ratingVal = "Default Rating", int watchedCounterVal = 0, int userRatingVal = 0, std::string userOpinionVal = "");
~Movie();
};
Movie.cpp:
#include "Movie.h"
// Name getter
std::string Movie::get_name() const
{
return this->name;
}
///*
// Destructor
Movie::~Movie()
{
std::cout << "Movie destructor called for: " << this->name << std::endl;
}
//*/
// Constructor
Movie::Movie(std::string nameVal, std::string ratingVal, int watchedCounterVal, int userRatingVal, std::string userOpinionVal) : name{ nameVal }, rating{ ratingVal }, watchedCounter{ watchedCounterVal }, userRating{ userRatingVal }, userOpinion{userOpinionVal}
{
std::cout << "Movie constructor called for: " << name << std::endl;
}
Movies.h:
#pragma once
#include<iostream>
#include<vector>
#include "Movie.h"
class Movies
{
private:
std::string listName;
std::vector<Movie> vectOfMovies;
static int listNumber;
public:
Movies(std::string listNameVal = "Default User's Movie List ");
~Movies();
std::string get_listName() const;
void addMovie(Movie m);
};
Movies.cpp:
#include<string>
#include "Movies.h"
int Movies::listNumber = 0;
// Constructor
Movies::Movies(std::string listNameVal) : listName{listNameVal}
{
++listNumber;
listName += std::to_string(listNumber);
std::cout << "MovieS constructor called for: " << listName << std::endl;
}
// Destructor
Movies::~Movies()
{
std::cout << "MovieS destructor called for: " << listName << std::endl;
}
std::string Movies::get_listName() const
{
return this->listName;
}
//Add movie to list of movies
void Movies::addMovie(Movie m)
{
this->vectOfMovies.push_back(m);
}
And the main .cpp file:
#include <iostream>
// #include "Movie.h"
#include "Movies.h"
int main()
{
Movies moviesObj;
moviesObj.get_listName();
return 0;
}
If the constructor/destructor is declared as private, then the class cannot be instantiated. If the destructor is private, then the object can only be deleted from inside the class as well. Also, it prevents the class from being inherited (or at least, prevent the inherited class from being instantiated/destroyed at all).
The use of having destructor as private:
Any time you want some other class to be responsible for the life cycle of your class' objects, or you have reason to prevent the destruction of an object, you can make the destructor private.
For instance, if you're doing some sort of reference counting thing, you can have the object (or manager that has been "friend"ed) responsible for counting the number of references to itself and delete it when the number hits zero. A private dtor would prevent anybody else from deleting it when there were still references to it.
For another instance, what if you have an object that has a manager (or itself) that may destroy it or may decline to destroy it depending on other conditions in the program, such as a database connection being open or a file being written. You could have a "request_delete" method in the class or the manager that will check that condition and it will either delete or decline, and return a status telling you what it did. That's far more flexible that just calling "delete".
So, I suggest that you could declare ~Movie(); as public. Then, the problem will be solved.
I have problem in defining constructors for classes and the way I have defined them earlier, doesn't work here properly.
This is for edx c++ intermediate course. when I try to define a class that inherits from some other class, referring to my base class with a constructor doesn't work properly and so my new class won't be defined correctly. What's the difference between the first use of constructors in the first code (using ":" notation that works properly), and the second one in second code (defining like function, that I have used before properly and doesn't work here)?
I have a base class called Person and a Student class that inherits from the base class. When I try to initialize a Student object that calls one of Person class constructors, it gives wrong answers. I think this is because of the way I define constructors. I make them like functions and initialize variables in curl braces. I have used this method earlier and it was working properly, but it doesn't work here. But the standard method using ":" before curly braces works properly here. I want to know what is the difference between these two?
Person.h:
#pragma once
#include <string>
class Person
{
private:
std::string name;
protected:
int age;
public:
Person();
Person(const std::string & name, int age);
void displayNameAge() const;
};
Person.cpp:
#include "pch.h"
#include "Person.h"
#include <iostream>
//Person::Person()
// : name("[unknown name]"), age(0)
//{
// std::cout << "Hello from Person::Person()" << std::endl;
//}
Person::Person()
{
name = "[unknown name]";
age = 0;
std::cout << "Hello from Person::Person()" << std::endl;
}
Person::Person(const std::string & name, int age)
{
this->name = name;
this->age = age;
std::cout << "Hello from Person::Person(string, int)" << std::endl;
}
//Person::Person(const std::string & name, int age)
// : name(name), age(age)
//{
// std::cout << "Hello from Person::Person(string, int)" << std::endl;
//}
void Person::displayNameAge() const
{
std::cout << name << ", " << age << std::endl;
}
Student.h:
#pragma once
#include "Person.h"
class Student : public Person
{
private:
std::string course;
public:
Student();
Student(const std::string & name, int age, const std::string & course);
void displayCourse() const;
};
Student.cpp:
#include "pch.h"
#include "Student.h"
#include <iostream>
Student::Student()
{
course = "[unassigned course]";
std::cout << "Hello from Student::Student()" << std::endl;
}
// first method: the right one
//Student::Student(const std::string & name, int age, const std::string & course)
// : Person(name, age), course(course)
//{
// std::cout << "Hello from Student::Student(string, int, string)" << std::endl;
//}
// second method: the wrong one
Student::Student(const std::string & name, int age, const std::string & course)
{
Person(name, age);
this->course = course;
std::cout << "Hello from Student::Student(string, int, string)" << std::endl;
}
void Student::displayCourse() const
{
std::cout << course << std::endl;
}
Main.cpp:
#include "pch.h"
#include "Student.h"
int main()
{
// Create a Student object using the no-argument constructor.
Student Student1;
Student1.displayNameAge();
Student1.displayCourse();
// Create a Student object using the parameterized constructor.
Student Student2("Jane Smith", 25, "Physics");
Student2.displayNameAge();
Student2.displayCourse();
return 0;
}
expected result:
Hello from Person::Person()
Hello from Student::Student()
[unknown name], 0
[unassigned course]
Hello from Person::Person(string, int)
Hello from Student::Student(string, int, string)
Jane Smith, 25
Physics
actual result:
Hello from Person::Person()
Hello from Student::Student()
[unknown name], 0
[unassigned course]
Hello from Person::Person()
Hello from Person::Person(string, int)
Hello from Student::Student(string, int, string)
[unknown name], 0
Physics
Initializer List
What you are missing is the initializer list.
Type::Type(Parameters)
: member1(init) // This is the initializer list
, member2(init)
{
Your code
}
If you do not explicitly provide one then the compiler will do it for you using the default constructor for the parent class then a call to the default constructor for each member.
So lets look at your class.
Student::Student(const std::string & name, int age, const std::string & course)
{
// Code
}
That is what you wrote. But this is what the compiler implemented.
Student::Student(const std::string & name, int age, const std::string & course)
: Person()
, course()
{
// Code
}
So because you did not do anything the compiler added it calls to the Person default constructor and course (std::string) default constructor.
Now the problem comes if your base class does not have a default constructor. Then the compiler can not add the appropriate calls and will generate a compiler error.
But there is also the issue that the way you are writing this is very inefficient as you are basically initializing all the members twice. Your calling the default constructor then in the Code section you are re-initializing the members with another value.
Student::Student(const std::string & name, int age, const std::string & course)
: Person(name, age)
, course() // Initialize it to empty here.
{
course = "[unassigned course]"; // Re-Initialize it with info.
}
You could simply do it once:
Student::Student()
: Person() // Note person must have a default constructor for this to work.
, course("[unassigned course]")
{}
Temporary Object
Student::Student(const std::string & name, int age, const std::string & course)
{
Person(name, age);
// CODE.
}
This is not doing what you think.
Lets add the initializer list.
Student::Student(const std::string & name, int age, const std::string & course)
: Person()
, course()
{
Person(name, age); // This is creating a person object localy.
// the person object has no name so is a
// temporary variable and goes out of scope
// at the ';'. So it is created and destroyed
// in place before other code is executed.
//
// This does not help initialize the class.
// It is creating a completely different
// and independent object.
// CODE.
}
You can see the execution here:
Hello from Person::Person() // Init parent
Hello from Person::Person(string, int) // Init the temp object.
// If you put a print in the destructor
// You will also see that executed
// Before the Student
// This is also why the object has "unknown name" and 0 age.
Hello from Student::Student(string, int, string) // Now we init the student
[unknown name], 0
Physics
Advice
Is there a valid scenario where you want initialized versions of the object? Personally I think not (if there are then ignore this) so get rid of the default constructors of Person and Student. Then you can not create uninitialized Students or `People.
Here's my code:
#include <iostream>
#include <string>
class Human
{
public:
std::string * name = new std::string();
void introduce();
};
void Human::introduce()
{
std::cout << "Hello, my name is " << Human::name << std::endl;
}
int main()
{
Human * martha;
martha->name = new std::string("Martha");
martha->introduce();
return 0;
}
Well, it's supposed to print a message out like:
"Hello, my name is Martha" but it doesn't print neither the "Hello, my name is" string or the "Martha" name. Why does it occur?
The fix is simple and is to completely remove all pointers; see the code below. There are a number of issues with your code that I could address in detail, including memory leaks, uninitialized variables, and general misuse of pointers, but it seems that you're possibly coming from a different language background and should spend time learning good practice and the important semantics and idioms in modern C++ from a good C++ book.
#include <iostream>
#include <string>
class Human
{
public:
std::string name;
void introduce();
};
void Human::introduce()
{
std::cout << "Hello, my name is " << name << std::endl;
}
int main()
{
Human martha;
martha.name = "Martha";
martha.introduce();
return 0;
}
Few modifications are required to the code.
Updated code along with the comments to the change made are included below.
#include <iostream>
#include <string>
class Human
{
public:
//Removed pointer to a string
//Cannot have an instantiation inside class declaration
//std::string * name = new std::string();
//Instead have a string member variable
std::string name;
void introduce();
};
void Human::introduce()
{
//Human::name not required this is a member function
//of the same class
std::cout << "Hello, my name is " << name << std::endl;
}
int main()
{
Human *martha = new Human();
//Assign a constant string to string member variable
martha->name = "Martha";
martha->introduce();
return 0;
}
As suggested by #alter igel - The Definitive C++ Book Guide and List would be a good place to start.
#include <iostream>
#include <string>
class Human {
public:
void Human(std::string* n) { name = n; }
void introduce();
private:
std::string* name;
};
void Human::introduce() {
std::cout << "Hello, my name is " << name << std::endl;
}
int main() {
Human* martha = new Human(new std:string("Martha"));
martha->introduce();
return 0;
}
Try that. The difference is that you don't initialise the variable in the class definition, and you initialise the name with the constructor. You can split the method definition out into it's own section, but it's only one line and is fine being inside the class definition.