【问题标题】:C++ const arguments in functions函数中的 C++ const 参数
【发布时间】:2017-07-20 10:42:11
【问题描述】:

我正在继续使用 C++ 学习 uni,但我遇到了一些关于指针、常量参数和类实现的所有基础知识的严重理解问题(与 C++ 相比,Java 中的这些实现非常简单)

我通常使用 Java,所以 C++ 对我来说非常陌生。

这是我的“Person”类的简单标题:

#ifndef Person_h
#define Person_h

class Person
{
private:
    char* name;
    char* adress; 
    char* phone;

public:
    Person();
    Person(char const *name, char const *adress, char const *phone);
    Person(const Person &other);
    ~Person();

    void setName(char const *name);
    char* getName() const;
    void setAdress(char const *adress);
    char* getAdress() const;
    void setPhone(char const *phone);
    char* getPhone() const;
};

#endif // !Person_h

问题从这里开始。为什么我应该使用 char 指针而不是实际的 char 变量?我猜这是为了节省内存或提高性能的一些约定?

这是我们教授编码的方式,并试图让我们理解指针和const等的使用。

现在这是我的类的实现:

#include "Person.h"
//Person.h class implementation

Person::Person()
{
    Person::name = new (char[64]);
    Person::adress = new (char[64]);
    Person::phone = new (char[64]);
}

Person::Person(const char *name, const char *adress , const char *phone)
{
    Person::name = new (char[64]);
    Person::adress = new (char[64]);
    Person::phone = new (char[64]);

    setName(name);
    setAdress(adress);
    setPhone(phone);
};

Person::Person(Person const &other)
{
    Person::name = new (char[64]);
    Person::adress = new (char[64]);
    Person::phone = new (char[64]);

    setName(other.getName);
    setAdress(other.getAdress);
    setPhone(other.getPhone);
};

Person::~Person()
{
    delete [] name;
    delete [] adress;
    delete [] phone;
};

void Person::setName(const char *name)
{
    this->name = name;
};

char* Person::getName() const
{
    return name;
};

void Person::setAdress(char const *adress)
{
    this->adress = adress;
};

char* Person::getAdress() const
{
    return adress;
};

void Person::setPhone(char const *phone)
{
    this->phone = phone;
};

char* Person::getPhone() const
{
    return phone;
};

我们应该学会手动为元素分配内存并尝试照顾整体内存管理。因此,对 setter 函数使用 const 参数。我想这是为了不改变元素参数?我很困惑,基本上……

而我的 IDE (MS VisualStudio 2015) 将以下行强调为错误:

void Person::setName(const char *name)
{
    this->name = name;    //error
};

“'const char *'类型的值不能分配给'char *'类型的实体”

那么当我无法分配这些值时,为什么要使用const?或者我怎样才能“un-const”那些,而不使成员变量本身const

这整件事现在对我来说只是一个很大的困惑。

编辑:我必须在考试中使用 C 字符串,这是为了了解指针和内存管理,参考我们的教授。

【问题讨论】:

  • > 为什么我应该使用 char 指针而不是实际的 char 变量? std::string。
  • 您应该使用std::string 来保存字符串数据,而不是裸指针。在我看来,您需要一本好的 C++ 书籍。
  • 在分配C风格的字符串时,不要使用=,而是使用strcpy来复制字符串值。
  • 在 C 和 C++ 中,指针可用于传递单个变量或变量数组。然而,指针本身不包含关于它是否包含单个项目的地址或数组内第一项的地址的信息。所以你需要从上下文中弄清楚。在您的情况下,name 被假定为指向以空字符结尾的字符数组(即 C 样式字符串)的指针。
  • @BoPersson 谢谢,现在我明白了......所以这都是与 C 相关的。想知道 C++ 中没有字符串,但我们使用 C 方面(如 C 样式字符串)来更好地理解“幕后”操作。

标签: c++ class pointers constants getter-setter


【解决方案1】:

通俗地讲,name 为 const 而this->name 为非const 时this->name = name; 不起作用的原因是因为您的函数承诺name 的内容将被视为读取-只是,但是通过将此指针分配给非常量指针,您可以随意修改数据,从而违反您的承诺。

你的老师显然是想用指针教你老式的 C++(本质上是面向对象的 C),所以你应该继续用字符串替换 char 指针。如果你这样做,你的老师可能会不高兴。

我们使用char* 而不是char[] 的原因有很多。

  • 一个原因是效率:如果可以传递char[],则需要将char[] 的全部内容复制到堆栈中。当您传递char* 时,您只是将指针复制到字符,这通常是单个机器字。

  • 另一个原因是它实际上是不可能的。编译器不知道您的 char[] 是以零结尾的事实,以便为其分配足够的堆栈空间并将其复制到堆栈中。该语言的创建者宁愿不将这种内置知识放入该语言中。相反,他们决定将char[] 隐式转换为char*,这样您就可以在函数中将其作为char* 接收,然后用它做您想做的事情。

  • 另一个原因是,如果您的 char[] 有点太大,那么您的堆栈就会溢出。

因此,由于所有这些原因,当我们想要传递比机器字更大(或相当大)的类型值时,我们不传递值本身,而是传递指向它们的指针或引用。

【讨论】:

  • 您不能在 c++ 中传递数组的副本。 char [] 隐式转换为 char *。没有传递数组这样的东西(只有一个指针 - 默认:按值复制)
  • @KostasRim 是的,我实际上已经写了“另一个原因是它实际上是不可能的......”
  • @KostasRim 你去吧,我希望那会更好。
【解决方案2】:

例如做

this->name = name;

存在问题的原因有两个:首先是因为您试图将一种类型的变量分配给密切相关但仍然不同类型的变量。但这不是大问题。

最大的问题是您尝试重新分配原始指针this->name(指向您已分配的一些内存)与另一个指针(指向其他地方)。

结果类似于

int a = 5;
int b = 10;
a = b;

然后想知道为什么a 不再等于5

这里有两种解决方案:第一种是继续使用指针,然后复制字符串,而不是分配指针。这是通过std::strcpy 函数完成的。

我推荐的解决方案是停止对字符串使用指针,而是使用标准 C++ std::string 类。然后你可以使用简单的赋值来复制字符串。它们还处理自己的内存,因此您不必担心内存泄漏、指针、释放无效指针或跟踪字符串的实际大小。

C++ 的std::string 类与Java 的String 类有一些相似之处,所以如果你有Java 背景,你应该不难适应。最大的不同在于,在 C++ 中使用 std::string 您实际上可以直接与 == 比较字符串。

【讨论】:

  • 在我的考试中必须使用 C 字符串以便更好地理解,这就是我们不使用标准 C++ 字符串的原因,但感谢您的解释,现在我得到了指针分配的真正问题。
【解决方案3】:

在现代 C++ 中,您应该仍然了解内存管理,但为了可读性、异常安全和错误,您应该使用容器,它为您完成工作,如 std::string。

const char *name 表示你有一个指针,它指向一个内存段,它本身就是 const,这意味着这个内存段内的数据不应该改变。

指针本身可以改变。

当你分配时

this->name = name;

您只是将指针 this->name 分配给 name 的指针。但是只有当指针是可转换类型时才能这样做。如果将 this->name 的类型从 char* 更改为 const char*,编译器不会抱怨。

但是在你分配新的东西之前,你应该清理内存,例如删除[] this->name

【讨论】:

  • 对于我的考试,我必须使用 C 风格的字符串,但感谢您的解释和清理内存的提示!
猜你喜欢
  • 2012-06-14
  • 2010-09-14
  • 2013-04-06
  • 1970-01-01
  • 2023-03-20
  • 2012-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多