整理了下c++入门的笔记。
目录
1、创建——>释放
(构造) (析构)
2、c是一种过程化程序,线性化
一、概念
- 对象(object):现实世界客观存在,可以相互区别事物
- 特点:a客观存在性 b 相互区别
- 特性:
- 属性:附着在对象上不可变化的特征(静态)
- 方法:对象可执行的操作(动态)
- 对象是类的实例化
- 同类对象:具有共同属性和方法的对象
- 类(class):具有共同属性和方法的对象的共性的抽象
- 抽象了一组同类对象的属性和方法
- 过程:抽象定义类的属性和方法
- 面向对象的特点:封装性和抽象性
二、定义类
class 类名{
private://私有访问权限
声明私有数据成员和方法成员
protected://受保护
声明受保护的数据和方法成员
public: //公有
声明公有数据成员和方法成员
};
- class必须小写
- 类名:必须符合标识符命名规则
- 属性——数据成员:数据类型成员名,可以是基本成员、数组、指针等
- 方法——成员函数:数据类型、函数名、形参
e.g.声明一个可以嘎嘎叫的鸭子类
class DUCK{
public:
void speak(){
printf("嘎!\n");
}
};
DUCK duck; //类实例化
duck.speak(); //调用对象函数
调用原则 1.有没有 2.访问权限够不够
三、类中属性的声明
- 在类中声明属性
- ·在类中声明什么属性、类的对象就具有哪些属性
-
类内访问权限:private:私有;protected:私有、受保护;public:私有受保护公有class myclass{ private:私有访问权限(被隐藏的成员) //类外对象不可访问自己的私有成员 //一个类的类外对象可以通过自己的公有访问私有,像函数调用访问、指针访问、引用访问等都是通过 public函数间接访问的 public:公有访问 //在类中声明的public的成员类外对象可直接访问 };
class MYCLASS{
private:int x,y;
void fun(){;}
public:int w;
void hun{
fun(); //类内成员调用不加对象名引用
}
void gun{;}
};
MYCLASS myclass;
//类内成员必须通过对象访问
//fun();
//gun();
//hun();
//对象不能直接访问类内私有
//my.x=1;
//my.y=1;
//my.fun();
my.w=1;
my.hun();
my.gun();
- 只要在类中声明,对象一定有,对象能否访问看访问权限;
- 类的对象初始化
- 画出类声明对象:类 对象名;//系统为对象分配单元。
- 必须通过公有方法访问私有数据
三、构造函数
- 在类中定义——成员函数
- 作用:完成对象的初始化
- 每创建一个对象,系统自动调用构造函数
- 创建多少个对象,就用多少次构造
- 如果系统没有声明构造,系统自动创建一个无参无内容的构造
3.创建
函数结构
- 函数名:与类名同名
- 无返回值类型
- 可以有参,可以无参
对象初始化:
- 类名:对象名(实参);
- 为对象分配单元
class MYclass{
private:
int x,y;
public:
MYclass(int i,int j)
{
x=i;y=j;
}
};
MYclass my(3,5); //初始化x=3,y=5;
- 构造参数可以无参,设置数据成员的默认值为0;
- 构造参数可以重载(参数个数或者参数类型 严格匹配)(兼容匹配:float——double char——int)(严格匹配:参数——参数 )
class MYclass{
private:
int x,y;
public:
MYclass()
{
x=0;y=0;
}
MYclass(int i,int j)
{
x=i;y=j;
}
};
MYclass my2; //初始化为0,第一个构造
MYclass my(3,5); //初始化x=3,y=5;第二个构造
构造函数的简化表示(熟练后写,不建议)
eg:输出一个三角形面积
#include <iostream>
using namespace std;
class Rectangle{
private:
int length,width;
public:
Rectangle()
{
length=0;
width=0;
}
Rectangle(int x,int y)
{
length=x;
width=y;
}
void Area()
{
return length*width;
}
};
int main()
{
Rectangle rect(7,4);
cout<<"面积:";
cout<<rect.Area()<<endl;
}
out:面积:28
eg2:声明一个类myclass,1.数据成员x、y(默认为0)2.功能有一个对象的数据成员的值复制给另外一个对象
class Myclass{
private:
int *px;
public:
Myclass(int *x) //不能用int x,函数执行完后x被释放,px没有被赋值
{
px=x;
}
void print()
{
cout<<*px<<endl;
}
};
int main()
{
x=3;
Myclass my(&x);
my.print();
}
四、指针——类指针(通过指针变量表示对象)
- 初始化指针对象:类名 *指针变量,eg:Myclass *p,my;
- 使指针变量有指向=指针变量=&对象名 p=&my;
- 通过指针变量,完成对指向对象的成员操作。
- 定义一个指向对象的指针变量时,指针变量不用调用构造
- 指针变量——>数据成员/方法名
class Myclass{
private:
public:
int x;
void print()
{
cout<<*px<<endl;
}
};
int main()
{
Myclass my,*pmy=&my;
pmy->print(); //*pmy.print();
pmy->x=1; //*pmy.x=1; //my.x //*(&my).x
}
五、动态对象
- 在内存系统中动态分配一个动态单元。
- 格式:
new 类名(); //必须有括号 new 类名(实参);
将在内存中分配一个对象单元,若分配成功,返回一个对象地址,else null;
- eg
Myclass *pmy=new Myclass(3,5); pmy->print(); //*pmy.print();/*(&Myclass.print())
new出来的是地址,需要用指针指向该地址。
- new完的必须delete!
六、析构函数
- 析构函数是一种在类内声明的成员函数。
- 特点:
- 与类名同名
- 无参,因此不能重载(构造可以)
- 格式:
~类名() {析构函数体 }
- 系统自动调用,释放一个对象时、进行销毁动作时、用new分配的动态对象释放时。
- 局部对象在运行阶段被释放,全局对象在编译阶段被释放。
- 析构函数的调用顺序严格和构造函数相反。
class Myclass{
private:
int *px;
public:
Myclass(int *x)
{
px=x;
}
~Myclass()
{
delete px; //释放new的指针
}
};
int main()
{
int *pmy=new Myclass(new int(3));
delete pmy; //释放对象
}
七、子对象
- 一次封装——>对象
- 使用子对象目的:二次封装
- 定义:类A的对象objA在类B中做数据成员。
-
class A{ //类A的定义 }; class B{ private: A objA; //生成A对象 int x; }; 例子: A为B的子对象 class A{ private: int x,y; public: void fun() { } }; class B{ private: A objA; //B的子对象 int z,x; public: void dofun() { objA.fun(); } }; int main() { B objB; objB.dofun(); //可通过B间接调用A }
调用和初始化操作和对象一样。
- 含有子对象的类的构造函数表示
-
类名(总形参):子对象(实参) { } class B{ private: A objA; //B的子对象 int z,x; public: B():A(3,5) { } };
含有子对象的类的构造调用:子对象先调构造,再执行自己的函数体。
八、继承
- 面向对象的一种共享机制,派生类是基类的继承
继承表示
class 基类名{
};
class 派生类名:继承权限 基类名{
}
eg:
class Base{
private:
int x,y;
public:
void A(){;}
};
class Derived:public Base{
private:
int z;
public:
void A()
{
Base::A(); //::基类作用域限定符,由于派生类和基类都有A函数
}
}
基类访问权限:
派生类访问基类权限
总结:
- 派生类继承基类私有,但不允许访问,基类私有只能被基类所访问。
赋值兼容规则
- 基类指针能够指向派生类对象。通过基类指针访问成员时,只可访问派生类从基类继承来的成员。
- 派生类指针不可指向基类对象。
eg
class Base{
public:
void fun(){}
};
class Derived{
public :
void fun(){};
};
int main()
{
Base *B=new Base();
Deried *D=new Derived();
Base *pb;Derived *pd;
pb=D; // 基类指向派生类
B->fun(); //B::FUN();
D->fun(); //D::FUN();
pb->fun(); //B:FUN();
//pd->fun();
}
派生类构造函数表示
- 派生类对象单元含有基类数据,在派生类构造函数中,需要调用基类构造。
- 调用顺序:
- 基类内部构造初始化。
- 派生类构造调用基类构造,完成在派生类内部基类初始化。
eg:
class Base{
private:
int x,y;
public:
Base()
{
x=0;y=0;
}
Base(int x,int y)
{
this->x=x;
this->y=y;
}
};
class Derived:public Base{
private:int z;
public:
Derived()
{
Z=0;
}
Derived(int i):Base(1,2):
{
}
};
含有子对象的派生类注意事项
- 含有子对象的派生类需要注意构造函数的表示:
派生类名(形参):基类名(实参),子对象(实参),子对象(实参)... { }
eg:如下逻辑关系:(细箭头表示子对象,粗箭头表示继承)
//子对象1
class Myclass{
public:
Myclass()
{
cout<<"myclass cons"<<endl;
}
~Myclass()
{
cout<<"myclass des"<<end;
}
};
//子对象2
class Yourclass{
public:
Yourclass()
{
cout<<"yourclass cons"<<endl;
}
~Yourclass()
{
cout<<"yourclass des"<<end;
}
};
//基类
class Base{
public:
Base()
{
cout<<"base cons"<<endl;
}
~Base()
{
cout<<"base des"<<endl;
}
};
//派生类
class Derived:public Base{
public:
Derived ():Base(),Myclass(),Yourclass() //构造!基类,子对象...
{
cout<<"derived cons"<<endl;
}
~Derived()
{
cout<<"derived des"<<endl;
}
};
int main()
{
Derived *pD=new Derived();
delete pD;
}
OUTS:
base cons
myclass cons
yourclass cons
derived cons
derived des
youclass des
myclass des
base des
构造顺序按照先基类,子对象,派生类顺序,按照构造后面调用顺序来
析构严格与构造相反
九、多态
多态是面向对象的理解点之一。
- 多态条件
- 有继承
- 基类里有虚函数
- 存在基类指针,用于指向不同的派生类,调用同一名称对象。
- 注意点
- 派生类的对象名必须和基类虚函数名一致
- 原则上需要派生类对象处理为虚函数,为了方便,可以只将基类名称前加 virtual 。
- 多态封装起来比较好,在多态时只需要改变封装类的形参(即哪个派生类)。EG:实现如下图,base为基类,两个派生类,一个A多态封装
//基类
class Base{
public:
virtual void fun()=0; //虚函数
};
class D1:public Base{
pubic:
D1():Base()
{
}
void fun()
{
}
};
class D2:public Base{
pubic:
D2():Base()
{
}
void fun()
{
}
};
class A{
private:
Base *base; //子对象
public:
A(base *t)
{
base=t;
}
void poly()
{
base->fun();
}
};
int main()
{
D1 *d1;
A *a=new A(d1);
a->fun();
}