5.4-day04-C++拷贝构造函数/静态成员
一、拷贝构造函数和拷贝赋值运算符
1.拷贝构造:用一个已有的对象,构造和它同类型的副本对象——克隆。
2.形如
class X {
X (const X& that) { ... }
};
的构造函数成为拷贝构造函数。如果一个类没有定义拷贝构造函数,系统会提供一个缺省拷贝构造函数。缺省拷贝构造函数对于基本类型的成员变量,按字节复制,对于类类型的成员变量,调用相应类型的拷贝构造函数。
3.在某些情况就下,缺省拷贝构造函数只能实现浅拷贝,如果需要获得深拷贝的复制效果,就需要自己定义拷贝构造函数。
4.形如
class X {
X& operator= (const X& that) {
...
}
};
的成员函数称为拷贝赋值运算符函数。如果一个类没有定义拷贝赋值运算符函数,系统会提供一个缺省拷贝赋值运算符函数。缺省拷贝赋值运算符函数对于基本类型的成员变量,按字节复制,对于类类型的成员变量,调用相应类型的拷贝赋值运算符函数。
5.在某些情况就下,缺省拷贝赋值运算符函数只能实现浅拷贝,如果需要获得深拷贝的复制效果,就需要自己定义拷贝赋值运算符函数。
练习:实现一个简化版的字符串类String支持:
1.用字符指针形式的字符串构造
2.拷贝构造和拷贝赋值
3.获取字符指针形式字符串的成员函数,类似string::c_str
说明:不得使用std::string!
二、静态成员
1.静态成员变量和静态成员函数是属于类的而非属于对象。
2.静态成员变量,为多个对象所共享,只有一份实例,可以通过对象访问也可以通过类访问,必须在类的外部定义并初始化。静态成员变量本质上与全局变量并没有区别,只是多了类作用域的约束,和访控属性的限制。
class Account {
private:
string m_name;
double m_balance;
static double m_rate;
};
3.静态成员函数,没有this指针,无法访问非静态成员。
4.单例模式
三、成员指针
Student s;
string* p = &s.m_name; // 不是
Student s2;
(一)成员变量指针
1.定义
成员变量类型 类名::*指针变量名;
string Student::*pname;
int Student::*page;
2.初始化/赋值
指针变量名 = &类名::成员变量名
pname = &Student::m_name;
page = &Student::m_age;
3.解引用
对象.*指针变量名
对象指针->*指针变量名
Student s, *p = &s;
s.*pname = "张飞";
cout << p->*page << endl;
(二)成员函数指针
1.定义
成员函数返回类型 (类名::*指针变量名) (参数表)
void (Student::*plearn) (const string&) const;
2.初始化/赋值
指针变量名 = &类名::成员函数名;
plearn = &Stduent::learn;
3.解引用
(对象.*指针变量名) (实参表);
(对象指针->*指针变量名) (实参表);
(s.*plearn) ("C++");
(p->*plearn) ("UNIX");
第三课 操作符重载
复数:3+4i
Complex
c1 - (c2 + c3)
c1.sub (c2.add (c3))
一、操作符标记和操作符函数
1.双目操作符:L#R
成员函数形式:L.operator# (R)
左调右参
全局函数形式:::operator# (L, R)
左一右二
2.单目操作符:#O/O#
成员函数形式:O.operator# ()
全局函数形式:::operator# (O)
3.三目操作符:不考虑
二、双目操作符
1.+/-/*//
操作数在计算前后不变。
表达式的值是右值。
complex.cpp
#include<iostream>
usingnamespace std;
classComplex{
public:
Complex(int r =0,int i =0):
m_r (r), m_i (i){}
void print (void)const{
cout << m_r <<'+'<< m_i <<'i'<< endl;
}
// 第一个const:返回右值
// 第二个const:支持常量型右操作数
// 第三个const:支持常量型左操作数
constComplexoperator+(
constComplex& r)const{
returnComplex(m_r + r.m_r, m_i + r.m_i);
}
private:0
int m_r;
int m_i;
friendconstComplexoperator-(constComplex&,
constComplex&);
};
constComplexoperator-(constComplex& l,
constComplex& r){
returnComplex(l.m_r - r.m_r, l.m_i - r.m_i);
}
int main (void){
constComplex c1 (1,2);
c1.print ();
constComplex c2 (3,4);
Complex c3 = c1 + c2;// c3 = c1.operator+ (c2)
c3.print ();// 4+6i
// (c1 + c2) = c3;
c3 = c2 - c1;// c3 = ::operator- (c2, c1)
c3.print ();// 2+2i
return0;
}
hungry.cpp
#include<iostream>
usingnamespace std;
// 饿汉方式
classSingleton{
public:
staticSingleton& getInst (void){
return s_inst;
}
private:
Singleton(void){}
Singleton(constSingleton&);
staticSingleton s_inst;
};
SingletonSingleton::s_inst;
int main (void){
Singleton& s1 =Singleton::getInst ();
Singleton& s2 =Singleton::getInst ();
Singleton& s3 =Singleton::getInst ();
cout <<&s1 <<' '<<&s2 <<' '<<&s3 << endl;
return0;
}
integer.cpp
#include<iostream>
usingnamespace std;
classInteger{
public:
Integer(int data =0): m_data (data){}
void print (void)const{
cout << m_data << endl;
}
/*
Integer (const Integer& that) :
m_data (that.m_data) {
cout << "拷贝构造" << endl;
}
*/
private:
int m_data;
};
void foo (Integer i){
i.print ();
}
Integer bar (void){
Integer i;
return i;
}
int main (void){
Integer i1 (10);
i1.print ();
Integer i2 (i1);// 拷贝构造
i2.print ();
Integer i3 = i1;// 拷贝构造
i3.print ();
// Integer i4 (10, 20);
cout <<"调用foo()函数"<< endl;
foo (i1);
cout <<"调用bar()函数"<< endl;
Integer i4 (bar ());
return0;
}
integer2.cpp
#include<iostream>
usingnamespace std;
classInteger{
public:
Integer(int data): m_data (newint(data)){}
~Integer(void){
if(m_data){
delete m_data;
m_data = NULL;
}
}
void print (void)const{
cout <<*m_data << endl;
}
Integer(constInteger& that):
m_data (newint(*that.m_data)){}
voidset(int data){
*m_data = data;
}
Integer&operator=(constInteger& that){
// 防止自赋值
if(&that !=this){
// 释放旧资源
delete m_data;
// 分配新资源
m_data =newint(*that.m_data);
// 拷贝新数据
}
// 返回自引用
return*this;
}
private:
int* m_data;
};
int main (void){
Integer i1 (10);
i1.print ();
Integer i2 (i1);
i2.print ();
i2.set(20);
i2.print ();
i1.print ();
Integer i3 (30);
i3.print ();// 30
i3 = i1;// 拷贝赋值
// i3.operator= (i1);
i3.print ();// 10
i3.set(40);
i3.print ();// 40
i1.print ();// 10
/*
int a = 10, b = 20, c = 30;
(a = b) = c;
cout << a << endl;
*/
(i3 = i1)= i2;
// i3.operator=(i1).operator=(i2);
i3.print ();
i3 = i3;
i3.print ();
return0;
}
lazy.cpp
#include<iostream>
usingnamespace std;
// 懒汉方式
classSingleton{
public:
staticSingleton& getInst (void){
if(! m_inst)
m_inst =newSingleton;
++m_cn;
return*m_inst;
}
void releaseInst (void){
if(m_cn &&--m_cn ==0)
deletethis;
}
private:
Singleton(void){
cout <<"构造:"<<this<< endl;
}
Singleton(constSingleton&);
~Singleton(void){
cout <<"析构:"<<this<< endl;
m_inst = NULL;
}
staticSingleton* m_inst;
staticunsignedint m_cn;
};
Singleton*Singleton::m_inst = NULL;
unsignedintSingleton::m_cn =0;
int main (void){
Singleton& s1 =Singleton::getInst ();
Singleton& s2 =Singleton::getInst ();
Singleton& s3 =Singleton::getInst ();
cout <<&s1 <<' '<<&s2 <<' '<<&s3 << endl;
s3.releaseInst ();
s2.releaseInst ();
s1.releaseInst ();
return0;
}
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225851192-2142302144.png)
memptr.cpp
#include<iostream>
#include<cstring>
usingnamespace std;
classStudent{
public:
Student(const string& name,int age):
m_name (name), m_age (age){}
double m_weight;
string m_name;
int m_age;
void learn (const string& lesson)const{
cout <<"我在学"<< lesson << endl;
}
staticvoid hello (void){
cout <<"你好!"<< endl;
}
};
int main (void){
string Student::*pname =&Student::m_name;
void* pv;
memcpy (&pv,&pname,4);
cout << pv << endl;
intStudent::*page =&Student::m_age;
memcpy (&pv,&page,4);
cout << pv << endl;
Student s ("张飞",25),*p =&s;
cout << s.*pname << endl;
cout << p->*page << endl;
Student s2 ("赵云",22);
cout << s2.*pname << endl;
void(Student::*plearn)(const string&)const=
&Student::learn;
(s.*plearn)("C++");
(p->*plearn)("UNIX");
void(*phello)(void)=Student::hello;
phello ();
return0;
}
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225851598-1301050717.png)
private.cpp
#include<iostream>
usingnamespace std;
classNocopy{
public:
Nocopy(void){}
private:
Nocopy(constNocopy&);
Nocopy&operator=(constNocopy&);
};
void foo (ostream os){
os <<"Hello, World !"<< endl;
}
int main (void){
Nocopy n1;
Nocopy n2 = n1;
Nocopy n3;
n3 = n1;
foo (cout);
- return0;
}
static.cpp
#include<iostream>
usingnamespace std;
class A {
public:
staticint m_i;
staticvoid foo (void){
cout <<"foo:"<< m_i << endl;
// m_d = 3.14;
// bar ();
}cd
double m_d;
void bar (void){
m_i =1000;
foo ();
}
};
int A::m_i =1;
int main (void){
A::m_i =10;
A a1, a2;
cout <<++a1.m_i << endl;
cout << a2.m_i << endl;
A::foo ();
a1.foo ();
a1.bar ();
return0;
}
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225852346-1858168500.png)
string.cpp
#include<iostream>
#include<cstring>
::usingnamespace std;
classString{
public:
String(constchar* str = NULL){
m_str =newchar[strlen(str?str:"")+1];
strcpy (m_str, str ? str :"");
}
~String(void){
if(m_str){
delete[] m_str;
m_str = NULL;
}
}
String(constString& that):
m_str (strcpy (
newchar[strlen(that.m_str)+1],
that.m_str)){}
/* 菜鸟
void operator= (const String& that) {
m_str = new char[strlen(that.m_str)+1];
strcpy (m_str, that.m_str);
}*/
String&operator=(constString& that){
if(&that !=this){
/* 小鸟
delete[] m_str;
m_str = new char[strlen(that.m_str)+1];
strcpy (m_str, that.m_str);
*/
/* 大鸟
char* str =
new char[strlen(that.m_str)+1];
delete[] m_str;
m_str = strcpy (str, that.m_str);
*/
// 老鸟
String temp (that);
swap (m_str, temp.m_str);
}
return*this;
}
constchar* c_str (void)const{
return m_str;
}
private:
char* m_str;
};
int main (void){
String s1 ("Hello, World !");
cout << s1.c_str ()<< endl;
String s2 = s1;
cout << s2.c_str ()<< endl;
String s3 ("Hello, Linux !");
try{
s1 = s3;
}
catch(exception& ex){
cout << ex.what ()<< endl;
}
cout << s1.c_str ()<< endl;
return0;
}
如果一个类没有定义拷贝构造函数,系统会提供一个缺省拷贝构造函数。缺省拷贝构造函数对于基本类型的成员变量,按字节复制,对于类类型的成员变量,调用相应类型的拷贝构造函数。
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">