C++类和动态内存分配(1)

时间:2022-03-20 20:01:51
 
 
C++中的类和动态内存分配,关键的问题如下:
1、调用构造函数的问题,创建对象时调用默认构造函数还是复制构造函数还是其他自定义构造函数?
2、需不需要自定义复制构造函数和重载赋值操作符;
3、类中成员的内存分配是怎样的,静态成员存储在哪里?
4、采用动态内存分配时要注意哪些问题?
示例代码如下所示:
<pre code_snippet_id="1707813" snippet_file_name="blog_20160604_1_2283670" name="code" class="cpp"><pre name="code" class="html">

 
/*
 * string1.h
 *
 *  Created on: 2016年6月1日
 *      Author: Administrator
 */

#include <iostream>
using std::ostream;
using std::istream;
#ifndef STRING1_H_
#define STRING1_H_


class String
{
private:
	char *str;
	int len;
	static int num_strings;
	static const int CINLEN=80;
public:
	String(const char *s);
	String(const String &s);
	String();
	~String();
	int length() const{return len;}

	String & operator= (const String &s);
	String & operator= (const char *s);
	char & operator[](int i);

	friend bool operator==(const String &s1,const String &s2);
	friend bool operator> (const String &s1,const String &s2);
	friend ostream & operator <<(ostream &os,const String &s);
	friend istream & operator >>(istream &is, String &s);

	static int HowMany();



};


#endif /* STRING1_H_ */
</pre><pre code_snippet_id="1707813" snippet_file_name="blog_20160604_10_9228863" name="code" class="cpp"><pre name="code" class="cpp">/*
 * string1.cpp
 *
 *  Created on: 2016年6月1日
 *      Author: Administrator
 */
#include <cstring>
#include "string1.h"
using std::cin;
using std::cout;

int String::num_strings = 0;

int String::HowMany()
{
	return num_strings;
}

String::String(const char *s)
{
	len = std::strlen(s);
	str = new char[len+1];
	std::strcpy(str,s);
	num_strings++;
}

String::String(const String &s)
{
	num_strings++;
	len = s.len;
	str = new char(len+1);
	std::strcpy(str,s.str);
    std::cout <<"调用复制构造函数\n";
}

String::String()
{
	len =0;
	str = new char[1];
	str[0]='\0';
	num_strings++;
}

String::~String()
{
	--num_strings;
	delete [] str;
}

String & String::operator =(const String &s)
{
	if(this == &s)
		return *this;
	delete [] str;
	len = s.len;
	str = new char[len+1];
	std::strcpy(str,s.str);
	return *this;

}

String & String::operator =(const char *s)
{
	delete [] str;
	len = std::strlen(s);
	str = new char[len+1];
	std::strcpy(str,s);
	return *this;

}

char & String::operator [](int i)
{
	return str[i];
}

bool operator ==(const String &s1,const String &s2)
{

	return (std::strcmp(s1.str,s2.str)==0);
}

bool operator >(const String &s1,const String &s2)
{
	return (std::strcmp(s1.str,s2.str)<0);
}

ostream & operator << (ostream &os,const String &s)
{
	os<<s.str;
	return os;
}

istream & operator >>(istream &is, String &s)
{
	char temp[String::CINLEN];
	is.get(temp,String::CINLEN);
	if(is)
		s = temp;
	while(is && is.get()!='\n')
		continue;
	return is;
}

 
<pre name="code" class="html">//============================================================================
// Name        : 4.cpp
// Author      : xie
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include "string1.h"

using namespace std;
const int size=5;
const int len=80;
int main() {
	String name;//调用默认的构造函数
	cin >>name;
	String name1(name);//调用复制构造函数
	String name2=name;//调用复制构造函数
	String name3=String(name);//调用复制构造函数
	String *name4 = new String(name);//调用复制构造函数

	cout << "name,name1,name2,name3,name4:"
		 <<name<<","<<name1<<","<<name2<<","<<name3<<","<<*name4<<";\n";
	cout<< "\nplease enter up to " <<size
			<<" short sayings(empty line to quit):\n";
	String sayings[size];
	char temp[len];
	int i;
	for(i=0; i<size; i++)
	{
		cout <<i+1<<":";
		cin.get(temp,len);
		while(cin && cin.get()!='\n')
			continue;
		if( !cin || temp[0]=='\0')
			break;
		else
			sayings[i]=temp; //重载赋值操作符
	}
	int total = i;
	for(i =0; i<total; i++)
	cout << i+1<< sayings[i] << endl;

	return 0;
}

1、调用构造函数的问题;

        String name;调用默认构造函数String();

        String myname("xie");调用构造函数String(const  char *s);

        String name1(name);//调用复制构造函数String(const String &s);
String name2=name;//调用复制构造函数String(const String &s);
String name3=String(name);//调用复制构造函数String(const String &s);
String *name4 = new String(name);//调用复制构造函数String(const String &s);

        String sayings[size];        

       char temp[10];

       sayings[i]=temp;         //调用赋值操作符函数String & operator= (const char *s);

2、当类成员中含有需要动态分配内存的指针时,需要自定义复制构造函数和重载赋值操作符

String name;

        String name2=name;

        如果没有重新实现复制构造函数,对象name2创建时将调用隐式的复制构造函数,name2.str = name.str,name2和name的str指针将指向同一个字符串,当对象消亡时将调用两次delete [] str,将字符串占用的内存释放了两次,将导致不可预料的后果。

       赋值操作符的问题和复制构造函数的问题一致,调用析构函数导致删除字符串内存两次。不同的地方在于,调用赋值操作符时,目标对象已经存在,由于目标对象可能引用了以前分配的数据,所以函数应使用delete [] 来释放这些数据,其次函数应避免将对象赋给自身,否则释放内存可能删除对象的内容。最后函数应返回一个指向对象的引用。

        if(this == &s)//避免赋给自身
return *this;
delete [] str;//释放目标对象指向的内容
len = s.len;
str = new char[len+1];
std::strcpy(str,s.str);
return *this;//返回指向对象的引用

3,类成员的内存分配问题

     类申明描述了如何分配内存,但并不分配内存,所以不能在类声明中初始化静态成员变量,静态类成员单独存储的,不是对象的组成部分,静态成员变量成为该类的所有对象共享的变量,

在类中声明static int num_strings,

则可在类定义中用作用域解析符初始化  int String::num_strings = 0;

特殊情况时,静态const整形和静态const枚举类型可以在类声明中初始化:

const static  int num=20;

const enum { num=20 };

可以将成员函数声明为静态的,静态成员函数不和特定的对象相关联,因此不能通过对象调用静态成员函数,可采用类名和作用域解析符来调用它

在main中  cout<< String::Howmang()<<endl;

静态成员函数只能访问静态数据成员,静态成员函数Howmany()只能访问num_strings,不能访问str和len。

4,new和delete,new []和delete []必须成对出现。