string class的实现

C/C++的基础终究还是不够牢实,今天随便写了一个String Class,反映出来的问题多多。先贴代码:

String.h

i nclude <string.h>
i nclude <stdio.h>

class String{
public:
 String(const char* str = NULL);
 String(const String& another);
 ~String(void);
 String& operator =(const String& rhs);
 void print();
private:
 char *m_data;
};

String.cpp

include "String.h"

String::String(const char* str)
{
   if(str == NULL)
   {
    m_data = new char[1];
       m_data[0] = '/0';
   }
   else
   {
    m_data = new char[strlen(str) + 1];
       strcpy(m_data,str);
   }
}

String::String(const String& another)
{

  //    delete[] m_data;  为什么没有这一句,这一句会出错。不会造成内存泄露吗?
    //不会,因为拷贝构造函数只有在对象创建的时候才会调用,而此时m_data还没有被分配内存,所以不会造成内存泄露。
    //
如果强制删除m_data,会出现错误“_BLOCK_TYPE_IS_VALID(pHead-&gt;nBlockUse)”,这表明m_data还没有备分配内存   //就已被释放了

  m_data = new char[strlen(another.m_data) + 1];
 strcpy(m_data,another.m_data);
}

String& String::operator=(const String& rhs)
{
if(this == &rhs)
return *this ;
delete []m_data; //
清除旧的内存空间
m_data = new char[strlen(rhs.m_data) + 1];
strcpy(m_data,rhs.m_data);
return *this ;
}

String::~String(void)
{
delete []m_data ;
}

void String::print()
{
    if(m_data == NULL) printf("No Content!/n");
 else {
  for(char *c = m_data; *c != '/0'; c++)
   printf("%c", *c);
  printf("/n");
 }
}

void main()
{
  char char_a1[6] = "hello";
  char char_a2[5] = {'a','b','c','e'}; 
  /*调用常规构造函数*/
  String s1(char_a1);    s1.print();
  String s2(char_a2);    s2.print();  
  /*调用拷贝构造函数*/
  String s3(s1);         s3.print();
  /* = 操作符函数*/
  s3 = s2;               s3.print();
}

代码无疑是正确的,但产生了几点思考,以QA的形式呈现出来:

Q1. m_data不是被申明为private级的么?为什么在String类拷贝构造和拷贝赋值的时候,能访问另外一个String类的私有成员变量?

A1. 这是一个简单得有些愚蠢的问题,Visualage总结得太好了:protection都是在class级别上的,而不是instance级别。由此延伸,我看到了这样一个例子:

class T
{
 protected string aaa;
public T(string val)
{
 aaa = val;
}
 public string GetString(T t)
 {
  return t.aaa;
 }
}

和以下两种用法:
1):
   T t1 = new T("test");
   Console.WriteLine(t1.GetString(t1));
2):
   T t1 = new T("test1");
   T t2 = new T("test2");
   Console.WriteLine(t1.GetString(t2));

请选择答案并说明理由:
a)
编译不通过
b)
第一种用法不能通过
c)
第二种用法不能通过
d)
都能通过

答案是d,不要说aaa限制成是protected,就是private,答案还是d

这样的问题是概念层面上的,归根到底的解释来源于编译器,有的事情是你我都无法知道的……

Q2. 你有没有注意到我是这么写的:char char_a2[5] = {'a','b','c','e'}; 为什么不写成 char char_a2[4] = {'a','b','c','e'}; 呢?

A2. 这个问题也是涉及到很C++语言很基础的部分,因为在常规构造中,我们用到了strlen(str),strlenstring.h的定义大概是这样的:

           int strlen(const char *c){

               if( c == NULL) return 0;

               int count = 0;

               while( *(c++) != '/0') count++;

               return count;

             }

看出问题来了么?对,strlen函数要检查形参的结尾'/0'(所以,一般传给strlen的参 数都是字符串)。如果我们传入了一块不以'/0'结尾的字符数组,可以想象:理论上来说,我们不清楚strlen在什么时候能返回一个整数,而由此,我们 动态分配的内存空间的大小也是未知的,完全由compiler决定。

为了达到目的(当然也是为了配合调用了strlen的内存动态分配),我们最好也似乎必须传入以'/0'结尾的字符数组(或者字符串)。

于是,我们写成了char char_a2[5] = {'a','b','c','e'}; 这种写法等同于char char_a2[5] = {'a','b','c','e','/0'};编译器会自动用'/0'补齐空位

勿在浮沙筑高台!强调编程基础的重要性,真是非常的重要啊!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值