1、复制构造函数 有指针和引用属性的应该使用深度复制 class_name(const class_name &);
如:
charin::charin(charin &in)
{
len = in.len;
sin = new char[len];
strcpy(sin,in.sin);
num_s++;
cout << len <<" bytes mem alloc!"<<endl;
cout << sin <<" deep copy in "<<num_s<<endl;
}
2、等值复制函数 有指针和引用属性的应该使用深度复制 如:
Stringbad & Stringbad::operator=(const Stringbad &st)
{
if(this == &st)
return *this;
delete [] str;
len = st.len;
str = new char[len+1];
std::strcpy(str,st.str);
return *this;
}
3、隐士转换函数 只有一个参数的构造函数会被用于隐士转换。可以使用explicit来避免 如 class a,int b; a = b;
4、强制转换 如上: class a,int b; b = a; 以及 int(a)等用到
模型为operator typename()
转换函数必须是类方法
转换数据不能指定类型
转换函数不能有参数
如:
operator int() const; //declear in class
operator doube() const;
stonew::operator int() const
{
return int (pounds + 0.5);
}
stonew::operator double() const
{
return pounds;
}
5、友元函数,某些不能转换的操作
比如:
A=B*2.75
转换为
A=B.operator*(2.75)
但是
A=2.75*B不能转换需要用到友元函数
A=operator*(2.75,b)
原型为
class operator*(double m,const class & t)
友元函数用于访问类中的私有数据,因为这部分是外部不能访问,
友元能够做到
注意:
友元函数必须在类中声明,但是他不是成员函数,不需要使用成员运算符来调用 比如.和-> 不需要用什么因为他的定义不使用::限定符
和成员函数访问权限相同,编写函数定义不需要使用::限定符,定义使用friend
另外需要注意友元又有调用不使用任何成员方式如.和->包括::,所以其方法实现应该放到class定义以外
如:
friend Time operator*(double m,const class & t);
Time operator*(double m,const Time & t) //在之后定义不能在class中定义这样就能找到方法
{
return t*m;
}
调用 直接 Time a=m*t;
这个调用会直接匹配到这个Time的有元函数
friend Time operator*(double m,const class & t)
6、构造
构造函数用于对对象的数据进行初始化,构造函数的和一般的方法(函数)有一些不同
他的名字必须是类的名字,不能带返回值。一般来说即使你不建立构造函数,也会
为你建立默认的构造函数,但是默认的构造函数是什么都不干的。如:
stu::stu(void){}
7、析构
析构函数用于对对象的内存进行回收,(如用malloc和new分配的内存空间)析构函数在
对象消亡的时候会被自动调用,而不需要你手动调用,名称为类名字前面加上~。一样
析构函数不能带返回值,并且析构函数没有参数,同样如果你设置析构函数,也会
为你默认建立析构函数,但是默认也是什么都不做的。
8、构造函数列表
当使用如下方式的时候需要使用构造函数列表初始化成员
1、const 成员
2、引用&成员
3、继承类的基类初始化
4、本生就是类的成员
如:
class base
{
private:
char *name;
public:
base(const char* myname);
base(const base & inc); //copy cons fun
virtual ~base(void){delete [] name;cout<<"test"<<endl;};
virtual int checkset(int cur_set);
};
class extrenl: public base
{
private:
const int id; //const
int &id2;//引用
string name; //对象类string 本生就是类
public:
extrenl(const int idi,const int &id2i,string names,base &inbase ):id(idi),id2(id2i),name(names),base(inbase){} ; //init list
extrenl(const char* myname,int mid);
virtual ~extrenl(void){cout<<"teste"<<endl;};
virtual int checkset(int cur_set);
};
其初始化顺序和列表中无关是按照声明的顺序进行的
9、静态static类成员函数
特别之处
1、声明必须包含定义
2、不包含THIS指针,在共有部分声明的static函数,可以使用类名和域解析运算符调用如
class test
private:
.....
static int num_str
public:
....
static int show(){return num_str;}
调用:
int cont = test::show();
也可以通过对象进行调用
test a;
a.show();
3、不和特定的对象相关联,只能访问静态数据成员,静态成员是全类对象共享的。
否则抛错:
报错test.h:20:7: error: invalid use of member ‘tests::c’ in static member function
但是普通成员函数可以调用 静态数据成员(必须先初始化)。
4、私有静态成员函数只能由类方法自己调用而不能使用 test::show()调用也不能用 a.show();
10、 静态数据成员
1、全部类对象共享一个静态成员
2、可以使用类型 类名和域解析运算符调用如 int test::num_str =0 进行赋值
公有static数据成员通过 test::num_str访问。
注意: int test::num_str =0 声明必须在声明为全局变量并且定义。
3、也可以在类中直接访问,但是不能构造函数中初始化。 必须在声明为全局变量并且定义。
4、私有static 数据成员也是用 int test::num_str =0 声明必须在声明为全局变量并且定义。但是私有static成员数据只能通过类方法访问
test::num_str不能访问。
报错
testcc.cpp:61:5: error: ‘int testa::total’ is private
int testa::total=1;
^
testcc.cpp:73:15: error: within this context
cout<<testa::total<<endl;
5、独有的一块静态内存区域,析构函数无用
!! 这应该是基于静态数据必须在类初始化前进行初始化的考虑。
!! 当然如果不断的循环调用这个类建立对象静态成员会不断增大或者变化,和C静态变量一样。知道main程序运行结束
关于静态函数和静态数据成员继承后使用的也是同一片区域,那么也就是说静态成员的基类和继承类数据共享</testa::total<<endl;
9和10的例子:
输出为:
6
20
3
0x602088
16
4
0x602088
0x400bca
0x400bca
可以看到地址都是相同的
</endl;};
</endl;};
</num_s<<endl;
</endl;
如:
charin::charin(charin &in)
{
len = in.len;
sin = new char[len];
strcpy(sin,in.sin);
num_s++;
cout << len <<" bytes mem alloc!"<<endl;
cout << sin <<" deep copy in "<<num_s<<endl;
}
2、等值复制函数 有指针和引用属性的应该使用深度复制 如:
Stringbad & Stringbad::operator=(const Stringbad &st)
{
if(this == &st)
return *this;
delete [] str;
len = st.len;
str = new char[len+1];
std::strcpy(str,st.str);
return *this;
}
3、隐士转换函数 只有一个参数的构造函数会被用于隐士转换。可以使用explicit来避免 如 class a,int b; a = b;
4、强制转换 如上: class a,int b; b = a; 以及 int(a)等用到
模型为operator typename()
转换函数必须是类方法
转换数据不能指定类型
转换函数不能有参数
如:
operator int() const; //declear in class
operator doube() const;
stonew::operator int() const
{
return int (pounds + 0.5);
}
stonew::operator double() const
{
return pounds;
}
5、友元函数,某些不能转换的操作
比如:
A=B*2.75
转换为
A=B.operator*(2.75)
但是
A=2.75*B不能转换需要用到友元函数
A=operator*(2.75,b)
原型为
class operator*(double m,const class & t)
友元函数用于访问类中的私有数据,因为这部分是外部不能访问,
友元能够做到
注意:
友元函数必须在类中声明,但是他不是成员函数,不需要使用成员运算符来调用 比如.和-> 不需要用什么因为他的定义不使用::限定符
和成员函数访问权限相同,编写函数定义不需要使用::限定符,定义使用friend
另外需要注意友元又有调用不使用任何成员方式如.和->包括::,所以其方法实现应该放到class定义以外
如:
friend Time operator*(double m,const class & t);
Time operator*(double m,const Time & t) //在之后定义不能在class中定义这样就能找到方法
{
return t*m;
}
调用 直接 Time a=m*t;
这个调用会直接匹配到这个Time的有元函数
friend Time operator*(double m,const class & t)
6、构造
构造函数用于对对象的数据进行初始化,构造函数的和一般的方法(函数)有一些不同
他的名字必须是类的名字,不能带返回值。一般来说即使你不建立构造函数,也会
为你建立默认的构造函数,但是默认的构造函数是什么都不干的。如:
stu::stu(void){}
7、析构
析构函数用于对对象的内存进行回收,(如用malloc和new分配的内存空间)析构函数在
对象消亡的时候会被自动调用,而不需要你手动调用,名称为类名字前面加上~。一样
析构函数不能带返回值,并且析构函数没有参数,同样如果你设置析构函数,也会
为你默认建立析构函数,但是默认也是什么都不做的。
8、构造函数列表
当使用如下方式的时候需要使用构造函数列表初始化成员
1、const 成员
2、引用&成员
3、继承类的基类初始化
4、本生就是类的成员
如:
class base
{
private:
char *name;
public:
base(const char* myname);
base(const base & inc); //copy cons fun
virtual ~base(void){delete [] name;cout<<"test"<<endl;};
virtual int checkset(int cur_set);
};
class extrenl: public base
{
private:
const int id; //const
int &id2;//引用
string name; //对象类string 本生就是类
public:
extrenl(const int idi,const int &id2i,string names,base &inbase ):id(idi),id2(id2i),name(names),base(inbase){} ; //init list
extrenl(const char* myname,int mid);
virtual ~extrenl(void){cout<<"teste"<<endl;};
virtual int checkset(int cur_set);
};
其初始化顺序和列表中无关是按照声明的顺序进行的
9、静态static类成员函数
特别之处
1、声明必须包含定义
2、不包含THIS指针,在共有部分声明的static函数,可以使用类名和域解析运算符调用如
class test
private:
.....
static int num_str
public:
....
static int show(){return num_str;}
调用:
int cont = test::show();
也可以通过对象进行调用
test a;
a.show();
3、不和特定的对象相关联,只能访问静态数据成员,静态成员是全类对象共享的。
否则抛错:
报错test.h:20:7: error: invalid use of member ‘tests::c’ in static member function
但是普通成员函数可以调用 静态数据成员(必须先初始化)。
4、私有静态成员函数只能由类方法自己调用而不能使用 test::show()调用也不能用 a.show();
10、 静态数据成员
1、全部类对象共享一个静态成员
2、可以使用类型 类名和域解析运算符调用如 int test::num_str =0 进行赋值
公有static数据成员通过 test::num_str访问。
注意: int test::num_str =0 声明必须在声明为全局变量并且定义。
3、也可以在类中直接访问,但是不能构造函数中初始化。 必须在声明为全局变量并且定义。
4、私有static 数据成员也是用 int test::num_str =0 声明必须在声明为全局变量并且定义。但是私有static成员数据只能通过类方法访问
test::num_str不能访问。
报错
testcc.cpp:61:5: error: ‘int testa::total’ is private
int testa::total=1;
^
testcc.cpp:73:15: error: within this context
cout<<testa::total<<endl;
5、独有的一块静态内存区域,析构函数无用
!! 这应该是基于静态数据必须在类初始化前进行初始化的考虑。
!! 当然如果不断的循环调用这个类建立对象静态成员会不断增大或者变化,和C静态变量一样。知道main程序运行结束
关于静态函数和静态数据成员继承后使用的也是同一片区域,那么也就是说静态成员的基类和继承类数据共享</testa::total<<endl;
9和10的例子:
点击(此处)折叠或打开
- #include
using namespace std;
class tests
{
private:
int c;
static int d;
static void adde(int int4)
{
d=d+int4;
}
public:
//static int d;
static int a;
static void adda(int in1)
{
a+=in1;
//d=1; 不能定义
//a+=c;报错test.h:20:7: error: invalid use of member ‘tests::c’ in static member function
}
tests(void){c=3;}
static int b;
static void addb(int in2)
{
b+=in2;
}
void addc(int int3)
{
c+=int3;
c+=a; //这里调用了静态数据成员a
cout<<c;
addb(a);//这里直接调用了静态函数成员
}
void addd(int int4)
{
d=d+int4;
addb(d);//调用静态成员函数和静态数据成员
adde(d);
cout<<d<<endl;
}
~tests(){}
};
class testsp:public tests
{
private:
int m;
public:
testsp(int in1):m(in1){}
};
</d<<endl;
</c;
-
- #include
#include"test.h"
#include
using namespace std;
//所以私有成员数据必须声明为全局并且赋值
int tests::a=1;//声明和定义,static 成员函数比如这样定义
int tests::b=2;
int tests::d=5;//私有static成员d也可以这样定义,但是函数不行
//int testsp::d=50;继承类继承了tests::a=1;不能在声明和定义并且是同一片内存区域
int main(void)
{
// int tests::a=1; 这样是不行的
tests::adda(1);//直接通过域解析符号::访问
tests::addb(2);
// tests::adde(4);静态不能访问‘static int tests::adde(int)’ is private
tests a;
a.addc(1);
a.adda(1);//通过对象访问静态成员函数
cout<<endl;
a.addd(5);
cout<<tests::a<<endl;
cout<<&tests::a<<endl;
cout<<tests::b<<endl;
testsp b(100);
testsp::adda(1);
cout<<testsp::a<<endl;
cout<<&testsp::a<<endl;
void (*p)(int)=testsp::adda;
void (*p1)(int)=tests::adda;
printf("%p\n",p1);
printf("%p\n",p);
}
</endl;
</testsp::a<<endl;
</tests::b<<endl;
</endl;
</tests::a<<endl;
</endl;
输出为:
6
20
3
0x602088
16
4
0x602088
0x400bca
0x400bca
可以看到地址都是相同的
</endl;};
</endl;};
</num_s<<endl;
</endl;