函数简单重载的问题

发布于 2024-10-18 00:24:05 字数 1600 浏览 0 评论 0原文

set 函数的想法:

第一个参数是引用,分配空间来保存测试的副本,设置 beany 的 str 成员指向新块,将测试复制到新块,并设置 beany 的 ct 成员。

问题:

1) 包含以下内容的行:

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

错误:表达式必须有一个类 类型

2) 包含以下内容的行:

temp[i] = cstr[i];

错误:表达式必须有 对象指针类型

3) 由于 const 的存在,字符串类型的函数 show() 重载无法找到匹配的函数签名

对于这些概念来说非常新,有人可以解释错误的原因吗?

#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;
}

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

好多鱼好多余 2024-10-25 00:24:05

我希望你不要认为这是针对你个人的......但是这段代码在很多逻辑层面上都有很多错误,在我看来它只是FUBAR

请帮自己一个忙,从阅读一本 C++ 书籍开始。可以在此处找到好的列表,您还可以找到互联网上免费的优质资源。

C++ 不是一种你(或任何其他人)可以通过输入一些字符并查看会发生什么来学习的语言......这对于 C++ 来说简直就是一种自杀式的方法。

编辑:

经过一些谷歌搜索后,您似乎确实在关注一本书。从我在网上找到的一些摘录来看,似乎是一本教授使用 C++ 编程的书。我认为这不是一个好主意,因为 C++ 太复杂,而且显然不合逻辑,无法成为程序员的第一门语言,而且很容易获得编译良好的程序,当你运行它们时,这只会让你发疯。然而,有一些专家认为这是一种可行的方法。

你的书确实被列出来,不是因为它好,而是因为它的书名接近一本好书。可能只是为了推销而采取的营销伎俩。

编辑2:

当你唯一的错误是选择一本糟糕的书来学习C++时,我为自己如此粗鲁感到有点抱歉。在这里尝试补偿是我试图告诉您的 C++ 代码中存在的所有问题:

1. 学习标准 C++

#include "stdafx.h"

如果您正在学习 C++,那么您应该尝试将微软告诉您的有关该语言的所有内容放在一边。标准 C++ 对于微软来说从来就不重要;可能是因为可移植代码对微软来说更多的是威胁而不是好处。

一旦您了解了 C++(但只有这样),如果您的平台是这样的话,就可以编写特定于 Microsoft 的代码。但了解什么是 MS-only 以及什么是 C++ 非常重要。在某些情况下,这种差异简直是愚蠢的,不值得考虑(例如,用于确定作用域或处理分配失败),但有时您实际上必须使用它们的语言变体来与 Windows 一起工作。

MS 开发工具很棒(或者至少它们是......例如,我只是喜欢 VC6),但它们总是试图欺骗您编写不可移植的代码。这是在 IDE 和 Windows API 示例中完成的。不要陷入这些陷阱:编写可移植代码,除非您确实需要特定于平台的代码并且始终要意识到这一点。

2. 不要污染全局命名空间

using namespace std;

这是一个坏主意。即使这有点烦人,如果您习惯在标准函数之前编写 std:: 也会好得多。原因是该语言中存在复杂的名称查找和重载解析规则,以及您在没有意识到的情况下进入命名空间的所有名称。

在 C++ 中,节省打字时间并不是那么重要(如果您正在编写一次性脚本,那么在 PERL 中,这一点很重要……但对于一般程序则不然)。更重要的是帮助谁阅读您的代码(包括您自己)并使用 std:: 来实现这一点。

3. 使用正确的主要声明

这又是关于不要落入愚蠢的 MS 陷阱。 main 的正确声明是:

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

在学习 C++ 时,你不应该使用任何其他东西。如果您使用的 MS 工具不允许您编写正确的声明(这并不奇怪),那么现在就把它放在地板上,然后使用一个尊重标准的工具来学习 C++。一旦你了解了 C++,如果你确实需要,你就可以开始使用不可移植的东西,但知道那是不可移植的东西。

Mingw 是一个很好的免费 Windows C++ 编译器,并且有 免费的优秀 IDE(如果您喜欢的话)。多年来,我越来越喜欢使用像 emacs (vim 也可以,我用了很多年)和一个命令行编译器,但主要是因为我工作在各种多种不同操作系统上的语言,没有一个 IDE 可以涵盖所有这些。我想将低级知识(如何复制一段文本、如何搜索字符串、如何要求完成、如何打开另一个文件)放在手指级别,而不必有意识地思考我在哪个 IDE 中只是为了找到正确的命令。如果您每次都必须思考 G# 的播放位置,那么您就无法真正演奏肖邦键盘。

不过,也许我只是老了......;-)

4. 选择合理的命名约定

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

在您的代码中,您将命名一个类stringy。如果您习惯了 C++ 中最常见的类命名约定(即将其命名为 Stringy),那就更好了。

标准 C++ 库不遵循此约定,但无论如何这些类将始终以 std:: 为前缀。

我的建议也是不要使用系统匈牙利表示法根据C++调用变量的想法有时会出现在 MS 文档中的类型(例如 iIndexsFileName)。这个想法不会扩展,仅仅意味着您将为所有变量使用错误的名称。

5. set 函数的问题

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];
}

在此函数中存在几个错误:

  • 您想要传递 char * 而不是 charchar 保存单个字符的空间,而您希望使用字符序列初始化 stringy 实例。在 C++ 中,您可以为此使用 char 指针,因为内存中对 char 序列有特定的支持,这些序列用特殊的 ascii char NUL 封闭(注意单个 "L" >,C++ 中的 ASCII NUL 字符拼写为 '\0',不要与 NULL 指针混淆)。 C++ 处理字符序列的首选方法实际上是 std::string 标准类,但也完全支持以 NUL 结尾的字符序列,以便与 C 向后兼容。

  • 然而,指针只是一个字符的地址...该字符后面会跟着其他字符,直到找到结束的'\0',但指针没有长度< /code> 成员(实际上根本没有成员,它是一个原始类型,如 intdouble)。

    要了解使用指针传递的字符序列的长度,可以使用标准函数 strlen (它返回序列中的字符数排除终止'\0')。所以你的代码可能应该是这样的:

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

我也一直在使用标准函数 strcpy 来复制字符序列,包括结束 '\0' 标记。 strcpy 的一个可能实现(这里只是为了展示以 '\0' 结尾的字符串的想法)如下:

    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. 内存分配

stringy 类的设计很糟糕(在 C++ 中,structclass 之间没有任何大的区别:只是可见性的默认值)。具体来说,构造和销毁没有在应该处理的地方(在 stringy 类内部)进行处理,并且对于以这种方式设计的类,也必须处理或禁止赋值和复制构造。

因此,您的程序只是忘记了释放内存泄漏(通常对于 main 来说不是一个严重的问题,但理解这个问题很重要)。

希望这个问题只是因为这本书还没有到来来解释这些概念。

无论如何,我觉得这本书很奇怪,它只讨论 new[] 但不讨论 delete[] (也许你的书没有被列为一本好书是有原因的) )。

在我看来,正确实现的 stringy 应该类似于:

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;
    }
};

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;
    }
};
柠檬色的秋千 2024-10-25 00:24:05

temp 是一个 const char*。该类型不提供任何类型的长度设施 - 它不是对象并且没有 length() 成员方法。使用 std::string - 这就是它的用途。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文