AlexanderAnderson
AlexanderAnderson

Reputation: 23

Problem with simple overloading of functions

The set functions' idea:

First argument is a reference, allocates space to hold copy of testing, sets str member of beany to point to the new block, copies testing to new block, and sets ct member of beany.

Problem:

1) Line that contains:

for (int i = 0; i < temp.length(); i++)

Error:expression must have a class type

2) Line that contains:

temp[i] = cstr[i];

Error: expression must have pointer-to-object type

3) overload of function show() for stringy type can't find matching function signature due to presence of const

Very new to these concepts, could someone explain the reason for the errors?

#include "stdafx.h"
#include <iostream>
using namespace std;
#include <cstring>
#include <cctype>
struct stringy {
    char * str; //points to a string
    int ct; //length of string(not counting '\0')
};

void set(stringy & obj,  char cstr);
void show(const stringy & obj, int times=1);
void show(const char * cstr, int times = 1);

int _tmain(int argc, _TCHAR* argv[])
{
    string beany;
    char testing[] = "Reality isn't what it used to be.";

    set(beany, testing);
    show(beany);
    show(beany, 2);
    testing[0] = 'D';
    testing[1] = 'u';
    show(testing);
    show(testing, 3);
    show("Done");
    return 0;
}

void set(stringy & obj, char cstr)
{
    char * temp = new char[cstr];
    obj.str = temp;
    for (int i = 0; i < temp.length(); i++)
    temp[i] = cstr[i];
}

void show(const stringy & obj, int times)
{
    for (int i = 0; i < times; i++)
        cout << obj.str;
}

void show(const char * cstr, int times)
{
    for (int i = 0; i < times; i++)
        cout << cstr;
}

Upvotes: 1

Views: 595

Answers (2)

6502
6502

Reputation: 114481

I hope you won't take this personally... but this code has so many errors on so many logical levels that in my opinion it's simply FUBAR.

Please do yourself a favor and start by reading a C++ book. A list of good ones can be found here and you can also find decent resources for free on the internet.

C++ is not a language that you (or anyone else indeed) can hope to learn by just typing it some characters and looking at what happens... that is simply just a suicidal approach to C++.

EDIT:

After doing some googling seems indeed that you are following a book. From a few excerpts I found on the net seems a book that is teaching programming using C++. I don't think this is a good idea because C++ is too complex and apparently illogical to be the first language for a programmer, also it's very very easy to get programs that compile fine and that will just drive you crazy when you run them. There are some gurus however that think this is a viable approach.

Your book is indeed listed, not because is good, but just because the title is close to one of a good book. Probably just a marketing trick to sell it.

EDIT2:

I felt a bit sorry for being so rude when your only fault is choosing a bad book to learn C++. To try compensate here is my attempt to tell all problems I think are present in your C++ code:

1. Learn standard C++

#include "stdafx.h"

If you are learning C++ then you should try to put aside everything that microsoft tells you about the language. Standard C++ has never been important for microsoft; probably because portable code is more a threat to microsoft than good for them.

Once you know C++ (but only then) it's ok to write microsoft-specific code if that is your platform. But it's important that you know what is ms-only and what is C++. There are cases in which the difference is just plain stupid and not worth considering (e.g. for scoping or handling of allocation failures) but sometimes you actually MUST use their variation of the language to work with windows.

MS development tools are great (or at least they were... I was simply in love with VC6 for example) but they will always try to trick you into writing unportable code. This is done both in IDEs and in the windows API examples. Don't fall into those traps: write portable code unless you have a real need for platform-specific code and be always be conscious about it.

2. Don't pollute the global namespace

using namespace std;

This is a bad idea. Even if it's a bit annoying it's much better if you get used to write std:: before standard functions. The reasons are because of the complex rules of name lookup and overload resolution that are present in the language and because of all the names that you are getting into your namespace without being conscious about them.

Saving typing time is not really that important in C++ (it's important in PERL if you are writing a throw-away script... but not for general programs). Much more important to help who is reading your code (and this includes yourself) and using std:: does that.

3. Use a proper main declaration

This is again about not falling in stupid MS traps. The correct declaration for main is

int main(int argc, const char *argv[])

You should never use anything else when learning about C++. If the MS tool you are using doesn't allow you to write a correct declaration (that wouldn't be a surprise) then just drop it on the floor now and learn C++ using a tool that shows some respect for the standard instead. Once you know C++ you can begin use non-portable stuff if you really need but knowing that's non-portable stuff.

Mingw is a good free C++ compiler for windows and there are free good IDEs if you like them. Over the years I got to like more using a good editor like emacs (vim is also ok, I used it for many years) and a command line compiler, but mainly because I work in a variety of languages on several different operating systems and no single IDE can cover all that. I want to put low level knowledge (how to copy a piece of text, how to search for a string, how to ask to completion, how to open another file) at a finger level and not having to think consciously in which IDE I am just to find the proper command. You cannot really play Chopin if you've to think every time to where G# is on the keyboard.

May be I'm just old, however... ;-)

4. Pick a reasonable naming convention

struct stringy {
    char * str; //points to a string
    int ct; //length of string(not counting '\0')
};

In your code your are naming a class stringy. It's better if you get used to what is the most common naming convention in C++ for classes, that is having it named Stringy instead.

The standard C++ library is not following this convention but those classes will always be prefixed by std:: anyway.

My advice is also to NOT use the idea of system hungarian notation of calling variables depending on the C++ type (like iIndex, sFileName) that is sometimes present in MS documentation. That idea doesn't scale up and simply means you will use bad names for all your variables.

5. Problems with set function

void set(stringy & obj, char cstr)
{
    char * temp = new char[cstr];
    obj.str = temp;
    for (int i = 0; i < temp.length(); i++)
    temp[i] = cstr[i];
}

In this function there are several errors:

  • You want to pass a char * not a char. A char holds the room for a single character and instead you want to initialize your stringy instance with a sequence of characters. In C++ you can use a char pointer for that because there is a specific support for char sequences in memory that are closed with the special ascii char NUL (note the single "L", the ASCII NUL character in C++ is spelled '\0' and is not to be confused with the NULL pointer). C++ preferred way for handling sequences of characters is actually the std::string standard class, but NUL-terminated sequences of characters are also fully supported for backward-compatibility with C.

  • A pointer is however just the address of a charater... that character will be followed by other characters until you find the closing '\0' but a pointer has no length member (actually has no members at all, it's a primitive type like int or double).

    To know the lenght of a sequence of characters that has been passed using a pointer there is the standard function strlen (that returns the number of characters in the sequence excluding the terminating '\0'). So your code should probably be something like:

    void set(stringy & obj, char *cstr)
    {
        char * temp = new char[1 + strlen(cstr)];
        obj.str = temp;
        strcpy(obj.str, cstr);
    }

I've been using also the standard function strcpy that does the copy of a char sequence including the end '\0' marker. A possibile implementation of strcpy (here just to show the idea of '\0'-terminated strings) is the following:

    char *mystrcpy(char *dest, const char *src)
    {
        int i = 0;
        while (src[i] != '\0')
        {
            dest[i] = src[i];
            i++;
        }
        dest[i] = '\0';
        return dest;
    }

6. Memory allocation

The stringy class is badly designed (in C++ there isn't any big difference between struct and class: just what is the default for visibility). To be specific construction and destruction are not handled where they should be (inside the stringy class), and for a class designed this way also assignment and copy construction must be handled or forbidden.

As a consequence your program is simply forgetting deallocation leaking memory (normally not a serious issue for main, but it's important to understand the problem).

Hopefully this problem is just because the book didn't arrive yet to explain those concepts.

Anyway I find it strange a book that talks about new[] but not about delete[] (may be there is a reason that your book is not listed as a good book).

A properly implemented stringy should IMO look something like:

struct stringy
{
    int size;    // Number of characters EXCLUDING ending '\0'
    char *ptr;   // Pointer to first character

    stringy(const char *s = "")
        : size(strlen(s)), ptr(new char[1 + size])
    {
        strcpy(ptr, s);
    }

    ~stringy()
    {
        delete[] ptr;
    }

    stringy(const stringy& other)
        : size(other.size), ptr(new char[1 + size])
    {
        strcpy(ptr, other.ptr);
    }

    stringy& operator=(const stringy& other)
    {
        char *newptr = new char[1 + other.size];
        strcpy(newptr, other.ptr);
        delete[] ptr;
        ptr = newptr;
        size = other.size;
        return *this;
    }
};

Upvotes: 3

Puppy
Puppy

Reputation: 146920

temp is a const char*. That type does not provide any kind of length facilities- it is not an object and does not have a length() member method. Use a std::string- that is what it is for.

Upvotes: 0

Related Questions