对象可以根据属性来区分,为了降低空间复杂度,可以让同类型对象共享一份成员函数。
1.编译器针对设计的类型分三步编译:
(1)识别和记录类中的属性(名称、类型、访问限定)
(2)识别和记录类中函数的声明
例如:对于以下代码,调用函数funa()时其内部调用func(),func()在funa()后面定义,故显示无法识别func(),除非先声明 void func(); 才可。
#include
using namespace std;
void funa()
{
func();
}
void func()
{
}
int main()
{
funa();//会显示无法编译通过
return 0;
}
而如果是类成员函数则可以编译通过。正是由于编译器对设计的类分三步编译(主要由于第二步):
#include
using namespace std;
class Fun
{
public:
void funa()
//void funa(Fun* const this)
{
func();//this->func();
}
void func()
//void func(Fun* const this)
{
}
};
int main()
{
Fun c1;
c1.funa();//funa(&c1);
return 0;
}
(3)改写在类中定义函数的参数列表(形参列表加入this指针,类名*const this)和函数体(出现成员变量的地方改为this->属性),改写对象调用成员函数的形式(c1.CountTotal变为CountTotal(&c1))。
下面为C++ 1.1中代码编译的效果(改写在注释中):
#include
using namespace std;
const int LEN{ 20 };
class CGoods
{
private:
char Name[LEN];
int Amount;
float Price;
float Total_Price;
public:
void RegisterGoods(const char*, int, float);
//void RegisterGoods(CGoods* const this,const char*,int,float);
void CountTotal();
//void CountTotal(CGoods* const this);
const char* Get_name();
//const char* Get_name(CGoods* const this);
int Get_amount(); //同理
float Get_price(); //
float Get_totalprice() //float Get_totalprice(CGoods* const this)
{
return Total_Price;
//return this->Total_Price;
}
};
//返回值类型 类名::函数名(参数列表){}
void CGoods::RegisterGoods(const char* name, int amount, float price)
//void CGoods::RegisterGoods(CGoods* const this,const char* name, int amount, float price)
{
strcpy_s(Name, LEN, name);
//strcpy_s(this->Name,LEN,name);
Amount = amount;
//this->Amount=amount;
Price = price;
//this->Price=price;
}
void CGoods::CountTotal()
//void CGoods::CountTotal(CGood* const this)
{
Total_Price = Price * Amount;
//this->Total_Price=this->Price * this->Amount;
}
const char* CGoods::Get_name() { return Name; }
int CGoods::Get_amount() { return Amount; }
float CGoods::Get_price() { return Price; }
float CGoods::Get_totalprice() { return Total_Price; }
int main()
{
CGoods c1;
c1.RegisterGoods("C++", 15, 29);
//RegisterGoods(&c1,"C++", 15, 29);
c1.CountTotal();
//CountTotal(&c1);
return 0;
}
2.仅有类成员函数有this指针(this指针实质为成员函数的一个形参,函数调用时产生this指针,函数调用结束this指针消失),全局函数也无this指针。
1.数据成员多为私有,要对其进行初始化,必须用一个公有函数来进行,该函数为构造函数(类成员函数,有this指针)。
构造函数作用:(1)创建对象;(2)初始化对象属性;(3)进行类型转换
构造函数特征:(1)函数名与类名同;(2)无返回类型(!=void),构造函数返回构造的对象;(3)构造函数在对象生存期内只被调用一次!(4)构造函数可以重载;(5)类中若未定义构造函数,则会自定义一个缺省的(无参、只可构造对象,不可初始化),无参构造函数=各参数均有缺省值=缺省构造函数
#include
using namespace std;
class Complex
{
private:
int Real;
int Image;
public:
Complex()
//Complex(Complex* const this)
{
Real = 0;//若不给值~为随机值
Image = 0;
}
Complex(int x, int y)
{
Real = x;
Image = y;
}
void Print()
{
cout << "Real:" << Real << " Image:" << Image << endl;
}
};
int main()
{
Complex c1;//调用无参构造函数,构造对象,不初始化
Complex c2(12, 23);//调用两参构造函数构造对象并初始化
c1.Print();
c2.Print();
return 0;
}
2.空间只能申请。有空间不一定有对象,有对象一定有空间。
#include
using namespace std;
class Empty
{
};
int main()
{
Empty a1;//由于分配空间,故需要占位符1个字节
cout << sizeof(a1) << endl;
}
3.虽然说构造函数在对象生存期内只被调用一次,但可以打破规则使用定位new实现2次调用(不要轻易进行二次调用)。
Complex c1; //c1调用构造函数初始化c1.Real=0,c1.Image=0
new(&c1) Complex(23,34); //定位new,再次调用构造函数重新对c1的属性初始化
4.缺省构造函数只能有一个!Complex(){} 和Complex(int x=0,int y=0){} 均代表缺省构造函数。
5.如下代码:c2对象无法创建,系统识别为函数的声明。
#include
using namespace std;
class Complex
{
private:
int Real;
int Image;
public:
Complex()
{
Real = 0;//若不给值~为随机值
Image = 0;
}
Complex(int x, int y)
{
Real = x;
Image = y;
}
};
int main()
{
Complex c1;
Complex c2();//c2对象无法创建,由于编译器会识别为函数的声明。
Complex c3(12, 23);
Complex c4 = Complex(1, 2);//编译器识别为:Complex c4(1,2);
c4 = Complex(12, 25);//与上一句不同,先产生一个新对象,再赋值。
Complex c5{};
Complex c6{ 2,3 };//优先采用!
return 0;
}
6.初始化!=赋值。初始化=构建对象时即赋值(效率高!)。
class Complex
{
private:
int Real;
int Image;
public:
Complex():Real{},Image{} //Real(0),Image(0)
{
//Real = 0;
//Image = 0;
}
Complex(int x, int y):Real{x},Image{y} //Real(x),Image(y) 初始化
{
//Real = x;//赋值
//Image = y;
}
};
如下代码:构造函数构建对象的次序是以类中成员属性设计的次序构建的!!与初始化列表次序无关。
#include
using namespace std;
class Complex
{
private:
int Real;
int Image;
public:
Complex(int x):Real{Image},Image{x}
{
}
void Print()
{
cout << "Real=" << Real << " Image=" << Image << endl;
}
};
int main()
{
Complex c1{3};
c1.Print();
return 0;
}