0

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!

Azeem
  • 11,148
  • 4
  • 27
  • 40
  • Your class `Book` doesn't have any member variables. Your constructor gets two parameters but you don't do anything with them, they are simply lost. – dlask Mar 28 '20 at 16:05

1 Answers1

2

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:

  1. 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.
  2. 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:

Azeem
  • 11,148
  • 4
  • 27
  • 40
  • Oh, so basically what happens in constructor, stays in constructor, you need to declare those members in struct or class itself? – Pierre Rigondeaux Mar 28 '20 at 16:10
  • @PierreRigondeaux: Yes. The class object needs to have some memory to store the data that it requires to use later. The arguments in the ctor are scoped to that ctor's body only. – Azeem Mar 28 '20 at 16:13
  • One more thing, is there an alternative to writing ```this->member = member```; ? – Pierre Rigondeaux Mar 28 '20 at 16:24
  • @PierreRigondeaux: You can have different names for data members and ctor/method arguments e.g. `name = name_;` then you don't have to use `this` pointer. – Azeem Mar 28 '20 at 16:29