C++ problem

Björn Lindberg d95-bli at nada.kth.se
Fri Aug 6 03:50:04 PDT 2004


michael <michael8110 at terra.com.br> writes:

> hello,i've been quite happily tinkering with C++ for the last few
> months,and i can't remember anything more enjoyable and stimulating in
> a  long time,which probably gives away ,well never mind.Problem is as
> follows:i'm trying to build a linked list database,so obviously i'll
> need  to put in some text,and that's where things are getting
> stuck.For  example,the below code,that would be more or less what i'd
> do to fill the  nodes with data,
> #include <iostream.h>
> class car
> {public:
> char itsName[20];
> };
> 
> int main()
> {char a[20]="citroen";
> car c;
> c.itsName=a;  //line 10
> cout<<a;
> return 0;
> }
> 
> returns
> test.cpp: In function `int main()':
> test.cpp:10: error: ISO C++ forbids assignment of arrays (WHY? i'm
> just  assigning a pointer here )

No, you are assigning an array, just like it says. C++ has stronger
typechecking than C has, and what you are trying to do doesn't make
any sense.

To do what you are attempting, you need to change the member variable
in car to a pointer, like this:

class car
{
public:
    char * itsName;
};

This is still not good though, because now you have a pointer in the
object to a stack variable. That pointer will point to nothing when
the stack variable is deallocated. Consider this (with the above
definition of car):

void name_car(car & c)
{
    char a[20] = "citroën";
    c.itsName = a;
}

int main()
{
    car c;
    name_car(c);
    std::cout << c.itsName << std::endl;
    // Oops! The a variable went out of scope when the name_car
    // function returned, and any attempt to access the string now
    // results in undefined behaviour.

    return 0;
}

So what is the solution? Don't use character arrays to represent
strings! Use the string class from the C++ standard library. It will
do exactly what you want:

#include <iostream>
#include <string>

class car
{
public:
    std::string name;
};

int main()
{
    std::string a("citroën");
    car c;
    c.name = a; // Here, the string is copied.
    std::cout << a << std::endl;
    a = "";
    std::cout << c.name << std::endl;    
    return 0;
}

As you will see when you run the above, the string is copied in the
assignment. This is important, because now the instance of the car
class c has ownership of its own string. With you first version, it
was sharing the string with the variable outside of the class, a. It
is an important element of object-oriented design in C++ that an
object has sole ownership of its constituents.

Design-wise, you could do even better though, by making use of
constructors and member variables. It is better if an instance is
initialized "in one go", instead of the user having to initialize it
over several lines. Here is a suggestion for you to study:

class car
{
public:
    car(std::string c) : _c(c)
    {}
    std::string name() // This member function is the only interface
                       // to the name of the object.
    {
	return _c;
    }
private:
    std::string _c;
};

int main()
{
    car c("citroën"); // Creating an object via the constructor
    std::cout << c.name() << std::endl; // Calling the member function
    return 0;
}

Finally, a couple of minor points:

  - As you can see from my code examples, the correct name of the
    header files does not have a .h suffix

  - The standard library classes and functions all exists within the
    namespace std. This means that you either have to specify them by
    using the 'std::' prefix (this is what I did above), OR import
    them all by writing 'using namespace std;' in your file, OR by
    importing specific names by writing eg 'using std::string;' in
    your file.

Use a recent version g++, and always compile with the switches '-Wall
-ansi -pedantic', and you will get maximum help from the compiler as
well.


Björn



More information about the lfs-chat mailing list