面向对象
在讨论C++ 构造函数 和 析构函数之前,需要了解一下面向对象这一概念.C++作为面向对象的编程语言,充分展示了面向对象的思想.
在字典中,“对象”被定义为:存在的或可被感知存在的事物。 (Athing presented to or capable of being presented to the senses.) 换句话说,对象可以是任何事物。“面向”的定义是:“被指向或针对
(directed toward)” .通常它使得“面向对象”成为一个形容词.
面向对象:被指向或针对你能够想到的任何事物。 ( object
oriented : directed toward just about anything you can think of)
面向对象三要素:抽象、封装和信息隐藏
抽象 是根据需求,捕获与问题相关的事物,描述与问题求解相关的该事 物数据和行为,忽略那些不重要的内容,得到对应于该事物的软件对象
封装 是根据需求为对象的数据提供外部访问接口
信息隐藏 使得对象的状态得以保持,只允许通过接口去修改对象的状态
这里需要区别C++的三大基本特征(侵删)
构造函数:
- 根据初始式,类对象的不同初始化方式由不同的构造函数来提供:
类对象的默认初始化和值初始化使用默认构造函数来完成
类对象的直接/参数初始化使用普通的参数构造函数来完成。
类对象的复制初始化使用拷贝构造函数或**拷贝赋值函数(移动构造函数)**来完成
2.浅复制和深复制问题:
对类进行复制的时候按位复制,即把一个对象各数据成员的值原样复制到目标对象中。当类中涉及到指针类型数据成员的时候,往往就会产生指针悬挂问题。
浅复制:
class String
{
public:
String(const char* cstr =0)
{
m_data = cstr;
}
private:
char* m_data;
};
char* str1="hello";
char* str2="word";
String s1(s);
String s2 = s1; //1
String s3(str2);
s3 = s1; //2
情况1:
s2=s1执行的是浅复制,s1.m_data和s2.m_date指向的是同一个内存地址,如果在析构函数里面有对内存的释放。就会出现内存访问异常。因为一块内存空间会被释放两次!
情况2:
s3 = s1执行的同样是浅复制,s1.m_data和s3.m_date指向的是不光同一个内存地址,s3原先指向"word"的内存由于没有进行销毁,出现内存泄漏问题
深复制:
class String:
#ifndef STRING_H
#define STRING_H
class String
{
public:
String(); //默认构造函数,如果在类定义时,未对构造函数进行重载,编译器将自动生成该函数
String(const char* cstr =0); //参数构造函数
//三个特殊函数Big Three
String(const String& str); //拷贝构造函数
String &operator=(const String& str); //拷贝赋值函数
~String(); //析构函数
char* get_c_str() const{return m_data; }; //成员函数
private:
char* m_data;
};
#endif // STRING_H
String.cpp:
inline String::String(const char *cstr)
{
if(cstr){
m_data = new char[strlen(cstr)+1];
strcpy(m_data,cstr);
}else {
//未制定初始值
m_data=new char[1];
*m_data='\0';
}
}
inline String &String::operator=(const String &str)
{
if(this == &str) //检查自我赋值,不可缺少,否则会出错
return *this;
//1.先释放m_data指向的空间
//2.为m_data申请需要的空间
//3.将str的值拷贝m_data
delete [] m_data;
m_data = new char[strlen(str.m_data)+1];
strcpy(m_data,str.m_data);
return *this;
}
inline String::~String()
{
delete [] m_data;
}
main.cpp:
int main()
{
String s1();
String s2("Hello");
String s3(s1);
cout << s3<<endl;
s3 = s2;
cout<<s3<<endl;
return 0;
}
深复制主要三步:
1.先释放m_data指向的空间
2.为m_data申请需要的空间
3.将str的值拷贝m_data