大纲:
1. 类函数
2. 构造函数, 析构函数, 拷贝函数
3.友元函数
4. 静态变量
5. this指针
--------------------------------------------------
1. 类和对象
类只是一种复杂数据类型的声明,不占用内存空间。而对象是类这种数据类型的一个变量
类只是一张图纸,起到说明的作用,不占用内存空间;对象才是具体的零件,要有地方来存放,才会占用内存空间
类和结构体的区别: 类里面可以放函数!
2. 类的创建方式
new 关键字,new出来的是指针, 指针操作,通过箭头—>, 指针不能用.对象才能用.
c++中,创建对象,是否要用new
有2种创建对象的方式!
可以不申请new, 直接用吗?
是的, 不new 直接用就是在栈中, 如果new就是在堆中!
反问: 对象岂不是没有空指针! 如果不new处理 ,不走构造函数??
可以在堆上创建也可以在栈上创建!
很重要: 如果是栈,对象在方法执行完释放了, 容易调用析构函数, 同时变量会被释放! 会产生很大问题(严重)
4. 类成员函数
成员函数可以声名, 成员函数也可以定义!
成员函数可以定义在类定义内部,或者单独使用范围解析运算符 :: 来定义,在 :: 运算符之前必须使用类名
在类定义中定义的成员函数把函数声明为内联的,即便没有使用 inline 标识符
类中的函数,入参数可以是Void?
类中可以定义成员函数, 没有执行题
need-to-insert-img
构造函数也是函数, 所以成员函数定义, 包括构造函数
// 成员函数定义,包括构造函数
Line::Line( double len)
{
cout << "Object is being created, length = " << len << endl;
length = len;
}
类.start() 访问方法的话, 要把方法的实现改成类函数才能访问的到!
need-to-insert-img
12. c++中::是什么意思
1).用于类成员函数
2).访问静态函数
3).用于静态变量的访问
总的来说: ::符号是用来访问函数的!
例如:声明了一个类A,类A里声明了一个成员函数void f( ),但没有在类的声明里给出f的定义,那么在类外定义f时, 就要写成void A::f( ),表示这个f( )函数是类A的成员函数。
不用 ::的话, 即使是public也不能访问到变量
need-to-insert-img
5. 构造函数中如何调用构造函数?
错误的写法, 构造函数不需要返回值
void Box::Box(){
}
应该是这样.和java一样
Box::Box(){
}
比如java中的自定义View
6.析构函数(只能有一个)
临终遗言:
java中的临终遗言是: finalize
析构函数(Destructor)也是一种特殊的成员函数,没有返回值,不需要程序员显式调用(程序员也没法显式调用),而是在销毁对象时自动执行
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源
classBox{
doublestate;
friendvoidstart(Boxbox);
public:
doublelength;
doublebreadth;
doubleheight;
voidset(doublelen,doublebre,doublehei);
doubleget();
Box();
~Box();
};
Box::~Box(){
cout<<"Box"<<"Box delete:"<<endl;
}
Box::Box(){
cout<<"Box"<<"Box create:"<<endl;
}
voidstart(Boxbox){
cout<<"start:"<<"ss:"<<endl;
}
doubleBox::get(){
returnlength*breadth*height;
}
voidBox::set(doublelen,doublebre,doublehei){
length=len;
breadth=bre;
height=hei;
}
intmain(){
Boxbox1;
box1.length=1.0;
box1.breadth=1.0;
box1.height=1.0;
box1.set(1.9,1.1,1.1);
start(box1);
cout<<"Box2 的体积:"<<box1.length<<endl;
return0;
}
结果: 析构函数执行了2次!
为啥2次, 方法释放的时候调用??还是因为又产生了一个对象!
应该是方法执行完, 栈被释放了. 然后就调用了析构函数!
BoxBox create:
start:ss:
BoxBox delete:
Box2 的体积:1.9
BoxBox delete:
分析: 用到了栈, 然后传递了对象!!
正确写法: 不要java那种写法, 应该传递地址!
析构函数:如果有在对象内部开辟堆内存,可以在析构函数中释放内存
用 new 分配内存时会调用构造函数,用 delete 释放内存时会调用析构函数()
new 创建的对象位于堆区,通过 delete 删除时才会调用析构函数;如果没有 delete,析构函数就不会被执行。
如果是 new 的对象,则必须调用 delete 才会调用到析构函数, 如果用了c的free会怎么样?
malloc/free 他们是一套, new/delete 它们是一套
malloc/free 不会去调用构造函数和析构函数
new/delete 会调用构造函数和析构函数
7. 拷贝构造函数 (很重要,会和析构函数相结合)
拷贝构造函数和构造函数哪个先执行?
调用构造函数调用拷贝构造函数并为指针 ptr 分配内存
一个对象给另外一个对象赋值:
Person person1={}
Person person2=person1;
赋值,是把所有的属性赋值了! 原理: 调用了拷贝构造函数!
这个拷贝是浅拷贝,拷贝的是值
使用场景:
1. 作为参数返回的时候会调用拷贝构造函数
2. 作为参数传递的时候会调用拷贝构造函数!
3. 一般要重写拷贝构造函数, 防止2次析构导致异常(释放)
classLine
{
public:
intgetLength(void);
Line(intlen);// 简单的构造函数
Line(constLine&obj);// 拷贝构造函数
~Line();
3.属性私有,公有--------->想到有友元函数!
关键字:privite和 public
默认情况下,类的所有成员都是私有的
8. 友元函数---->为了访问类的私有函数或者属性 (我么是朋友, 我可以访问你)
友元函数是不能用类::freind
类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。
友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend
注意: 1. 友元函数定义在类里面声明, 不要在函数的实现里面定义!
2. 友元函数的作用,是让你可以通过方法访问类的私有属性,而不是方法方法私有性!
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
所以定义的时候,这样定义
friend void start(Box box);
need-to-insert-img
6.1 友元函数与普通函数的区别
友元函数:直接方法名调用。
普通函数:需要对象名::+方法名 调用
友元类是: 一个类里面放另一个类的定义! 哪个类定义了友元,服务于他本身!
#include<iostream>
usingnamespacestd;
classCCar;//提前声明CCar类,以便后面的CDriver类使用
classCDriver
{
public:
voidModifyCar(CCar*pCar);//改装汽车
};
classCCar
{
private:
intprice;
friendintMostExpensiveCar(CCarcars[],inttotal);//声明友元
friendvoidCDriver::ModifyCar(CCar*pCar);//声明友元
};
voidCDriver::ModifyCar(CCar*pCar)
{
pCar->price+=1000;//汽车改装后价值增加
}
intMostExpensiveCar(CCarcars[],inttotal)//求最贵气车的价格
{
inttmpMax=-1;
for(inti=0;i<total;++i)
if(cars[i].price>tmpMax)
tmpMax=cars[i].price;
returntmpMax;
}
intmain()
{
return0;
}
9. 静态变量和静态函数
c++没有静态类, 但是有静态变量和静态方法!
内存中位置: 栈? 堆? 常量池?
它在常量池中, 不在栈, 也不在堆中!
静态属性在c++中必须要出时候,初始化必须这么写, 静态成员变量必须初始化,而且只能在类体外进行! 否则报错,如下
need-to-insert-img
static int objectCount;
定义初始化这么定义:
int Box::objectCount=10;
而不是这样;
static int objectCount=10;
可是有时候我们希望在多个对象之间共享数据,对象 a 改变了某份数据后对象 b 可以检测到。
共享数据的典型使用场景是计数,以前面的 Student 类为例,如果我们想知道班级中共有多少名学生,就可以设置一份共享的变量,每次创建对象时让该变量加 1
我们可以使用静态成员变量来实现多个对象共享数据的目标。
运算符 :: 来重新声明静态变量从而对它进行初始化
类的静态成员变量为什么必须得在类外初始化?
我的理解: 由于静态变量在编译期间必须初始化,全局变量的静态或者非静态的变量都可以赋初值0。而类中的变量要用构造函数来初始化,但是在编译期间没有创造对象,所以就没有运行构造方法。故在编译期间没有给类的静态变量初始化。所以要在类外 main之前要给该静态变量初始化,不管该静态变量的作用域为private还是public,因为编译期间private没有影响。但是一旦进入运行时,就不可以调用类中的private变量。
static int objectCount;
cout << "Total objects: " << Box::objectCount << endl;
2. static 关键字
总结:
静态的属性定义时**必须要初始化** (实现) int Student::tag = 12;
静态 可以直接用类名去操作 :: Student::tag += 12;
静态的方法只能去操作静态的属性或者方法
10.自带this指针
this 是 const 指针,原因: 他是共享的, 它的值是不能被修改的.
在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。
不用this, 在类的内部, 也可以访问里面的变量和访问,那么为什么还要this?
和java一样, 为了防止全局变量名和局部变量名!
友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。
有指针, 指针访问变量或者函数可以通过 -->的方式!
需要对 C 结构有基本的了解,并懂得如何使用箭头 -> 运算符来访问结构成员。
cout << "月: "<< 1 + ltm->tm_mon<< endl;
void func() {
static int val;
}
中,变量 val 的内存地址位于:
A. 已初始化数据段
B.未初始化数据段
C.堆
D.栈
【标准答案】B
11. 要定义.h文件,原因是!
12. 对象大小