#ifndef D1_STRINGBAD_H #define D1_STRINGBAD_H #includeclass stringbad { private: char * str; int len; static int num_strings; //静态成员变量,只创建一个静态副本 public: stringbad(const char *s ); stringbad(); ~stringbad(); friend std::ostream &operator<<(std::ostream &os, const stringbad &st); }; #endif //D1_STRINGBAD_H
#include "stringbad.h" #includeusing std::cout; int stringbad::num_strings = 0; //初始化静态变量成员,单独初始化 stringbad::stringbad(const char *s) //构造函数 { len = std::strlen(s); str = new char[len + 1]; std::strcpy(str,s); num_strings++; cout << num_strings << ": "" << str << "" object createdn"; } stringbad::stringbad() //默认构造函数 { len = 3; str = new char[4]; std::strcpy(str,"C++"); num_strings++; cout << num_strings << ": "" << str << "" default object createdn"; } stringbad::~stringbad() //析构函数 { cout << """ << str << "" object deleted, "; num_strings--; cout << num_strings << " leftn"; delete[] str; } std::ostream &operator<<(std::ostream &os, const stringbad &st) { os << st.str; return os; }
静态变量和类:
将静态成员num_strings的值初始化为零时,注意,不能在类声明中初始化静态变量,这是因为声明中描述了如何分配内存,但并不分配内存。对于静态成员变量,可以在类声明之外使用单独的语句来进行初始化,这是因为静态类成员是单独存储的,而不是对象的组成部分。初始化是在方法文件中,而不是在类声明文件中进行的,这是因为类声明位于头文件中,如果头文件被多个文件包含,变量就会被多次初始化,引发错误。const变量可以在类声明中初始化静态数据成员:static const int num_strings = 12;
构造函数和析构函数:
如果类成员是一个指针,构造函数应该先分配足够的内存来存储(使用new动态分配),然后再把内容复制到内存中;
stringbad::stringbad(const char *s) { len = std::strlen(s); str = new char[len + 1]; //string是一个指针 std::strcpy(str,s); num_strings++; cout << num_strings << ": "" << str << "" object createdn"; }
在构造函数中用new分配内存,在析构函数中就要用delete删除内存;
- 当对象过期时,指针str也将过期,但是new分配的内存不会被释放,除非使用delete释放,,如果使用new[ ],则释放时用delete [ ] str;
特殊成员函数:
默认构造函数:创建对象时会调用构造函数,如下,定义一个类Klunk,创建对象时:
Klunk lunk();
此时没有传入任何参数,因此调用默认构造函数:
Klunk::Klunk()
{}; //里面可以定义默认值
复制构造函数:用于将对象复制到新创建的对象中,即用于初始化过程
1.函数原型:类名(const 类名 &);
2.何时调用复制构造函数:
将新对象显式地初始化为现有对象:
stringbad ditto(motto);
stringbad metoo = motto;
stringbad also = stringbad(motto) ;
stringbad *pstingbad = new stringbad(motto);
2.函数按值传递或函数返回对象时:(按值传递意味着创建副本)
void callme2(stringbad sb)
{...};
3.默认的复制构造函数的功能:逐个复制静态成员的值,称为浅复制
stringbad sailor = sports;
即:
stringbad sailor;
sailor.str = sports.str;
sailor.len = sports.len;
//这里不是复制字符串,而是复制一个指向这个字符串的指针,得到的是两个指向同一个字符串的指针,当一个指针释放内存时,另一个所指向的内容也被改变,因此会出现错误。
可以改成深度复制:
stringbad::stringbad(const stringbad & st)
{
num_strings++;
len = str.len;
str = new char [len+1];
std::strcpy(str,st,str);
}
赋值运算符:
stringbad knot;
knot = headline1; //这才是赋值,不是初始化;
stringbad knot = heandline1; //这是初始化,不一定会用到赋值运算符;
同样会有上述浅复制的问题,可以编写赋值运算符:
原型:类名 & 类名::operator=(const 类名 &);
stringbad & stringbad::operator=(const stringbad & st)
{
if (this = &st)
return *this;
delete [ ] str;
len = str.len;
str = new char [len+1];
std::strcpy(str,st.str);
return *this;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)