通过此指针的成员变量和函数

时间:2018-09-13 00:56:20

标签: c++

#include <iostream>
#include<cstring>

using namespace std;
class String
{
    private:
    char *sptr;

    public:
    String()
    {

     }

    String(char str[])
    {
      sptr = new char[strlen(str) + 1];
      strcpy( sptr, str );
    }

    String(const String& source)
    {

        sptr = new char[strlen(source.sptr) + 1];
        strcpy( sptr, source.sptr);

    }

    ~String()
    {
      delete sptr; 
    }

    String operator=( const String& other )
    {

        if(&other!=NULL)
        {

            String tmp( other );   
            sptr = new char[strlen(tmp.sptr) + 1];
            strcpy( sptr, tmp.sptr);
        }
        return *this;    
    }
    void display()
    {

      for( char const* p = sptr; *p != '\0'; ++ p) {
            std::cout << *p;
        }
        cout<<endl;

    }


};

 int main()
 {

   String a1;
   String a2("Hello ");   
   String a3(a2);

   a2.display();
   a3.display();

    //a2.change("Java ");
    a2.display();
    a3.display();
}

程序的输出

Hello Hello Hello Hello.

但是我无法在代码中进行以下更改...即,在Main()中,我创建了以下对象

String a1;
String a2("Hello ");   
String a3(a2);

a2.display();
a3.display();

//a2.change("Java ");
a2.display();
a3.display();

我想用Java更改对象a2(注释),并希望输出为

Hello Hello Java Hello 

通过this指针对Data成员进行深层复制。

  
    

如何将Hello字符串更改为Java

  

1 个答案:

答案 0 :(得分:2)

由于String类中的错误,不能使用您的String类来构建程序。您必须先解决这些错误,然后再考虑将String用作字符串类。

因此,此答案首先解决了如何解决String的问题-从那里开始,您现在就可以编写程序,知道您没有在错误的基础上工作。


错误1:默认构造

在默认构造sptr时,您未能初始化String。因此,当执行~String()时,对delete的调用将尝试delete一个未初始化的指针。

简单的1行main功能如下:

int main()
{
   String s;
} // <-- destructor of s may crash

将显示不确定的行为,并可能崩溃,如this example所示。

要解决此问题:

class String
{
   public:
     String() : sptr(nullptr) {}
   //...
};

现在,在delete []上发布sptr时,不会发生伤害,因为delete []nullptr是完全有效的(基本上是无操作)。


错误2:赋值运算符错误

您的String::operator=无法取消分配先前分配的内存。此外,NULL的检查不正确,因为&other将始终为true

我假设这是对自我分配的检查,但是书写不正确。通过将当前对象(this)的地址与传入的对象的地址进行比较来完成自我分配检查:

if (this != &other)

一旦有了,就可以这样编写其余的函数:

if(this != &other)
{
    String tmp( other );   
    std::swap(tmp.sptr, sptr);
}
return *this;

此函数所做的全部工作就是将other复制到名为String的临时tmp中,将sptr换成tmp.sptr并让{{1}用旧数据消亡。这就是所谓的copy / swap idiom,在这里您只是将当前对象的内容与临时对象的内容交换出去,而让临时对象与旧内容一起消失。

请注意,使用复制/交换时无需进行自我分配检查,但是进行此项检查没有任何危害(当存在自我分配检查时,甚至可以做一个很小的优化)。

编辑:另一个问题是tmp应该返回对当前对象的引用,而不是全新的operator=对象。签名应为:

String

错误3:String& operator=( const String& other ) // <-- note the return type is String& { //... code //... return *this; } 的格式错误

由于使用delete进行分配,因此您应该使用new [],而不仅仅是析构函数中的delete []

delete

鉴于所有这些更改,下面的代码不再有问题,如Live Example here所示。

现在您有了一个有效的~String() { delete [] sptr; } 类,然后可以从那里构建您的应用程序。


对于您的程序,您可以使用赋值运算符轻松更改字符串。不需要String函数:

change()

由于String a2("Hello "); a2.display(); a2 = "Java "; a2.display(); 不再存在上述更改的问题,因此现在可以毫无问题地完成分配。