一般开发项目使用类中使用内联函数、
类内初始值,C++11才支持
默认构造函数:
1)白动调用 (在创建新对象时,自动调用)
2)构造函数的函数名,和类名相同
3)构造函数没有返回类型
4)可以有多个构造函数 (即函数重载形式)
构造函数的种类:
默认构造函数
自定义的构造函数
拷贝构造函数
自动合成的拷贝构造函数存在风险(是浅拷贝 ),当成员是指针的时候,指向同一个地址
//以下调用拷贝构造函数
Object h2 = h1;
Object h3(h1);
//自定义拷贝构造函数
Object(const Object &);
为了数据的安全,应该在定义接口的时候对象加上const,const对象只能调用const方法:
void showMsg(const Object &object){//使用引用,避免创建新的对象
cout<<object.getName()<<endl;
}
void getName() const;//在方法后面加const,该方法中不允许成员变量的修改
什么时候调用拷贝构造函数:
1.调用函数时,实参是对象,形参不是引用类型如果函数的形参是引用类型,就不会调用拷贝构造函数
2.函数的返回类型是类,而且不是引用类型
3.对象数组的初始化列表中,使用对象。
赋值构造函数
//以下情况调用赋值构造函数
Object h1,h2;
h1=h2;//已经存在了,再赋值
//构造自定义赋值构造函数
Object& operator = (const Object& other){
//防止对象给自己赋值,h1=h1
if(*this == other)
return *this;
name = other.name;
strcpy(addr, other.addr);
return *this;//返回引用,防止链式处理,h1=h2=h3
}
析构函数:对象销毁时,自动调用
~Object()//和类同名,前面加波浪号
{
delete addr;//释放堆内存
}
类内静态static方法中,只能访问static数据成员(因为会产生歧义),也不能调用这个类的非static方法,静态数据成员不能使用this指针,静态类内成员变量定义好后,不再属于这个对象,而是一个单独的内存,静态对象不能在类内直接初始值(加了const的静态成员变量可以在类内初始化,但是不要在类内的类外初始化两次),要在外部进行初始化,初始化时不需要再带有static字样,使用类名可以直接访问public的静态成员变量,
//类的静态成员函数
static int count;
//&+对象为取地址符号
int Object::count = 0;//类外初始化
类文件的分离:
实际开发中,定义类的头文件 ,头文件包含类的定义,类内的方法只有声明,具体的实现在同类名的cpp文件中
const变量
const string c = "";//const变量在类内初始,C11支持
const变量还可以在构造函数自动赋值,const不可以在方法内进行初始化,const 对象不可以访问非const方法,因为非const方法会改变变量的值,方法后加了const关键字后,不能改变任何数据成员
void Object(int a, int b): c(b){
//把参数b赋值给c成员变量,初始化列表
}
组合与聚类,数据成员是对象的时候,生命周期和其拥有者一致,
//当数据成员是对象的时候也可以,对象是成员的非指针的时候是组合关系,
//指针为聚合关系,指针可以指定指向哪个对象
Computer::Computer(const char * cpuBrand, const char *cpuVersion, int hardDisk, int memory):cpu(cpuBrand, cpuVersion)
{
this->hardDisk = hardDisk;
this->memory = memory;
//this->cpu = new cpu(cpuBrand, cpuVersion)
}
//以上cpu定义时为,也可以定义为指针,在构造函数中需要new一个对象,在析构函数中需要释放内存delete cpu
private:
Cpu cpu;
//Cpu *cpu;
//宏定义_FUNCTION_,用于打印当前函数的名称
cout<<__FUNCTION__<<endl;
聚合举例,当对象成员是指针,通过方法指向某个成员对象的时候,改对象消亡,指向的成员对象不消亡,当对某个对象只是使用关系,而不是完全占有的关系的时候
//需要包含的某个对象简单声明
class B;
class A{
public:
void addB(B *b){//使用改方法指向某个对象,析构函数的时候不需要释放b,因为只是指向关系
this->b = b;
}
private:
B *b;
}
const变量不能直接赋值给引用类型存在风险,作为参数赋值的时候必须加const才能赋值
const Object object;
test(object);//会出错
void test(const Object &object){
object.play();
}
继承与派生:
除了“析构函数”和“构造函数”,父类所有成员函数,以及数据成员都会被子类继承
继承方式有:
公有public继承,继承公共的类和变量,并且父类所有类型数据成员继承过来类型不变,子类不能直接访问private私有成员,需要把父类的成员private----->protected
私有private继承,父类所有类型的数据成员继承过来后都会变成私有的
protected继承,父类所有类型的数据成员继承过来后public会变成protected的
// 创建子类对象时,会调用构造函数!
// 会先调用父类的构造函数,用来初始化从父类继承的数据
// 再调用自己的构造函数,用来初始化自己定义的数据
没有体现父类的构造函数那就会自动调用父类的默认构造函数!!!
子类重载父类方法的时候,子类对象调用方法时,先在自己定义的方法中去寻找,如果有,就调用自己定义的方法如果找不到,就到父类的方法中去找,如果有,就调用父类的这个同名方法/如果还是找不到,就是发生错误!
Son::Son(const char *name, int age,const char *game) : Father(name,age){
cout<<__FUNCTION__<<endl;
this->game = game;
}
派生类对象的内存分布:
父类的数据成员先分布,子类自己的数据成员后分布,函数不占内存
子类构造函数调用顺序:
1、静态数据成员对象构造函数
2、父类构造函数
3、普通数据成员对象构造函数
4、子类构造函数
子类的析构函数和子类构造函数调用相反
子类对象可以直接赋值给父类对象,父类对象不能赋值给子类对象,同理,父类的指针可以指向子类对象指针,但是子类对象指针不能指向父类对象指针,父类的引用可以指向子类对象
多重继承:继承多个父类,多继承构造函数的顺序和写的时候顺序一致,多重继承存在二义性(多个父类中存在同名函数或者属性)
1、需要在方法/属性前加上指定类名的限定
2、在子类中重新定义该方法,在方法中通过指定父类名来指定重名方法
检查类的内存分布:在C/C++ -> 命令行里添加:/d1 reportSingleClassLayoutXXX(XXX是类名),重新编译会在输出窗口的生成里看到对象布局和虚表布局。
虚继承:被共享的基类叫虚基类,可以很好的解决菱形继承
class B : virtual public A{
}
友元函数、友元类,在需要使用类的私有成员中声明函数/类,该类/函数可以访问该类的私有成员
使用成员函数在类中实现运算符重载
使用非成员函数在类中实现运算符重载(利用友元函数)
//需要在Cow中定义该友元函数
Pork operator+ (const Cow& cow1, const Cow& cow2){
int tem = cow1.weight *2 + cow2.weight*3;
return Pork(tem);
}
在调用时:首先查找有没有成员函数,再查找友元函数实现