int a[3] = { 0,1,2 };//数组
char cl[3];//类C字符串逐个位赋值,cl = "zla"不合法--C++提供字符串类"string"
cl[0] = 'z';
cl[1] = 'l';
cl[2] = 'a';
//cin >> cl;
for (int i = 0; i < 3; i++)
{
cout << cl[i]<< endl;
}
struct Person
{
string name;
int age;
char sex;
float height;
};
Person p1 = { "Wei",27,'W',175};
声明:
class 类名
{
public:
外部调用方法
属性get,set;
private:
属性
}
//在类外部定义“类中声明的方法”(必须加以“::”作为域限定符,用于声明函数属于哪个类)
函数返回值 类名::函数名(参数)
{
方法体;//在类内实现定义的函数系统能够默认为内联函数。
}
内联函数(避免方法在栈空间中频繁存取释放):只有在类外定义的成员函数规模较且调用频率较高时,才将成员函数指定为内联函数,(返回值2加inline ,类中的声明同样加上inline)。
成员访问:
1.对象名.成员名;
2.指针->成员名
3.引用名.成员名
类:get,set方法:读写类的私有成员(保护作用)。
类:成员函数:
类的成员函数声明与实现,分离;
在头文件".h"文件中进行类的声明;
在源代码/程序文件".cpp"文件中进行类成员函数的实现;
在主函数"main.cpp"文件中使用类 的成员函数;
Re.h文件
cood<>
using namespace std;
calss Re
{
public:
int Area();
int Perimeter;
int getLength();
void setLength(int Len);
int getWidth();
void setWidth(int Wid);
private:
int length,width,
}
Re.cpp文件:
#include "Re.h"//引入要实现类的头文件
int Re::Area()
{
return length*width;
}
int Re::getLength ()
{
return length;
}
void Re::setLength(int Len)
{
length = Len;
}
main.cpp主函数
#include "Re.h"//引入使用类头文件,预编译时使用Re.h中的内容替换引用
using namespace std;
int main (int arge,char *argv[])
{
}
构造函数:类名();{}
1)无返回值,非void
2)可以有多个构造函数,根据参数类型重载
3)类对象创建时自动调用(new调用,delete调用析构函数)
1、在类类内定义
class Re
{
public:
Re()//构造
{
length = 1;
width = 1;
}
}
2、在类外定义
Re::Re()
{
length = 1;
width = 1;
}
带参数构造函数:类名(类型 形参);
class Re
{
public:
Re(int Len,int Wid)//构造
{
length = Len;
width = Wid;
}
}
参数初始化表对数据成员初始化:
class Re
{
public:
Re(int Len,int Wid):length(Len),width(Wid) {}//"{}"不能省略
private:
int length,windle;
}
默认参数值构造函数:用户不指定是,编译器使用默认值
Re(int Len = 1,int Wid = 2)//构造
{
length = Len;
width = Wid;
}
析构函数:~与类名相同 ()前面加上“~”
1)与构造函数对应用于释放对象所占用内存(并不是删除对象),由delete调用
2)析构函数同样没有返回值,但也没有参数由于没有参数也不能重载,一个类存在多个构造函数但只存在一个析构函数。
3)析构函数也可用于最后一次使用类对象后执行的操作(写在方法体中)
4)后创建的对象先被释放
5)静态局部对象在函数执行结束时不调用析构函数,只在main函数结束或调用exit函数时才调用。
6)对于全局对象,当程序离开其作区域时调用i构造函数。
class Re
{
public:
Re(){}
~Re(){}
}
new malloc区别
1、 new分配内存按照数据类型进行分配,malloc分配内存按照指定的大小分配;
malloc 是函数,开辟内存需要传入字节数,如 malloc(100);表示在堆上开辟了 100 个字 节的内存,返回 void*,表示分配的堆内存的起始地址,因此 malloc 的返回值需要强转成指 定类型的地址;new 是运算符,开辟内存需要指定类型,返回指定类型的地址,因此不需要 进行强转。
2、 malloc 和 new 都是在堆上开辟内存的,malloc 只负责开辟内存,没有初始化功能,需要 用户自己初始化;new 不但开辟内存,还可以进行初始化,
3、 malloc 开辟内存失败返回 NULL,new 开辟内存失败抛出 bad_alloc 类型的异常,需要捕 获异常才能判断内存开辟成功或失败,new 运算符其实是 operator new 函数的调用,它底 层调用的也是 malloc 来开辟内存的,new 它比 malloc 多的就是初始化功能,对于类类型来 说,所谓初始化,就是调用相应的构造函数。
4、 new分配的内存要用delete销毁,malloc要用free来销毁;delete销毁的时候会调用对象的析构函数,而free则不会。
CONST
共有数据
常量数据成员:const在不同位置标示不同含义:
const int aa//使用const的普通数据成员常量
const int * bb//在int前使用const的指针数据成员
int const cc//在int后使用const的指针数据成员
const int const dd//在int类型前后使用const的指针数据成员
const int &cc //使用const的引用类型成员
1)aa为整型常量,初始化后不能被改变,(在类中,必须在构造函数的初始化列表中进行初始化(不能在类定义时初始化:const int aa = 5//错误))
2)在指针数据类型前时:指针指向的值不能改变
3)在指针数据类型后时:指针变量值不能改变
4)在指针数据类型前后时:指针指向值与指针值都不改变
常量创建后不能将整型常量的地址赋值给一个int指针,应赋值给cosnt int指针。
const int mm = 30;
int *pp = &mm;//应改为:const int *pp = &mm
C++允许创建指针常量,所指向的普通变量不是常量:
int mm = 30;
const int *pp = &mm;//可以将非常量赋值给指针常量,但不能通过pp改变mm值。
常成员函数:
声明:
void showDate() const;//const在参数列表后。
定义:
void Class::showDate() cosnt//在调用时不需加const
{
方法体;
}
常类对象:
声明
Re const r1 = {len = 2; wid = 3;}//定义常队形时必须进行初始化,而且其数据成员不能被更新(数据成员变为const)。
注意:如果一个对象被声明为常对象,则通过该常对象只能调用它的常成员函数(不能调用非const型成员函数)(系统自动隐式调用的)构造/析构除外).
静态成员:
声明:
static flot AccounntSum;
初始化:
float AccountRecord::AccountSum = 0;//C++中静态成员必须在类外进行,不能在构造函数中(C#中可定义静态构造函数用于初始化静态成员)
1)静态字段 仅仅存储一份 所有对象共享 常驻内存中
2)静态方法只能访问静态成员(非静态成员依赖于对象生成) ,非静态方法静态非静态都可以访问,
3)*不能实例化,只能包含静态成员, 静态类不能被继承(工具类)
/* 静态适用
* 利:单独空间存储,所有对象共享,可直接被类名调用
* 弊:静态方法中只能访问静态成员,共享数据被多个对象访问时会出现并发。
* 适用场合:
* 1.所有对象需要共享的数据。
* 2.在没有对象是就要访问成员。
* 3.工具类适合做静态类(常用,不需要过多数据)
继承,派生:
继承的语法:class 子类 : 继承方式 父类
多继承语法::class 派生类 :继承方式1 基类1,继承方式2 基类2....
{
派生类新成员;
}
继承方式一共有三种:
- 公共继承
- 保护继承
- 私有继承
**问题:**从父类继承过来的成员,哪些属于子类对象中?
父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到(子类的sizeof包括子类成员以及所有父类成员//包括私有成员)
父类的方法也是单独储存的,子类调用时由this指针指向调用的对象实现调用。
**问题:父类和子类的构造和析构顺序是谁先谁后?
继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
派生类构造函数:
派生类名::派生类名(arg_derived_list):基类名(arg_base_list)
{
//派生类新增数据成员初始化语句;
}
派生类存在与基类同名函数时使用,基类::函数名()来调用基类同名函数 (::作用域符)
多态(C++以(纯)/虚函数实现多态:C#则在C++的虚函数基础上分出虚函数,抽象类接口(纯虚函数)
1)虚函数
class 基类
{
public:
virtural 函数返回值 虚函数名(形式参数表)
{
函数体
}
}
class 派生类: public 基类
{
public:
virtual 函数返回值 虚函数名(形参表)//virtual可不写出,派生类中与基类同名函数默认为虚函数
{
函数体;
}
}
C++中不采用虚函数时,通过定义多个指向各派生类的指针来调用派生类中同名的函数。
pt>函数名();
虚函数,指针指向派生类时,调用同名方法为运行期绑定(动态)非编译期绑定。(动态绑定通过实际指向类的虚函数表获取函数地址)
运行期绑定只通过指针/引用来操作,采用定向直接调用函数将采用编译期绑定来调用虚函数
构造函数与析构函数
构造函数不能时虚函数,析构函数可以是虚函数。
(1)为什么父类的析构函数必须是虚函数?(虚析构)
当我们动态申请一个子类对象时,使用基类指针指向该对象,如果不用虚函数,基类指针在析构时,子类的析构函数不能得到调用,也就是为了在释放基类指针时可以释放掉子类申请的空间,防止内存泄漏.
析构函数声明为虚函数后,通过指针来删除所指向的对象时,编译器进行运行期绑定,由于基类型指针实际指向的是派生类对象,则派生类析构函数被调用,随后基类析构函数被调用,(析构函数调用时沿着继承树自下而上进行,通过将析构函数声明为虚函数,来保证下层派生类析构函数得到调用,防止内存泄漏)
纯虚析构:
virtual Animal() =0;//在类中声明纯虚析构后需在类外实现纯虚析构,
Animal::Animal()
[
函数体;
]
(2)为什么C++默认的析构函数不是虚函数?
因为虚函数需要额外的虚表指针指向虚函数表,占用额外的内存4字节。而对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。
纯虚函数:在虚函数声明的结尾加上“=0”(派生类必须实现基类的纯虚数)(公共接口)
一个类只要拥有一个纯虚函数,它就是抽象类(包含纯虚函数的类时无法创建对象的)
基类
public:
virtual float SurfaceArea()=0;
vitual float Volme()=0;
派生类
public Cube:public Base
{
public:
Cube(float len):length(len){}
float SurfaceArea();
float Volume();
private:
float length;
};
float Cube::SurfaceArea()
[
函数体
]
友元/friend (使外部,全局/局部函数,类,作为本类的友元,使其可以访问本类中的私有成员)
1)全局函数做友元
class Building
{
//告诉编译器 goodGay全局函数 是 Building类的好朋友,可以访问类中的私有内容
**friend void goodGay(Building * building);**
public:
Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}
public:
string m_SittingRoom; //客厅
private:
string m_BedRoom; //卧室
};
void goodGay(Building * building)
{
cout << "好基友正在访问: " << building->m_SittingRoom << endl;
cout << "好基友正在访问: " << building->m_BedRoom << endl;
}
void test01()
{
Building b;
goodGay(&b);
}
int main(){
test01();
system("pause");
return 0;
}
2)类做友元
class Building;
class goodGay
{
public:
goodGay();
void visit();
private:
Building *building;
};
class Building
{
//告诉编译器 goodGay类是Building类的好朋友,可以访问到Building类中私有内容
**friend class goodGay;**
public:
Building();
public:
string m_SittingRoom; //客厅
private:
string m_BedRoom;//卧室
};
Building::Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}
goodGay::goodGay()
{
building = new Building;
}
void goodGay::visit()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
cout << "好基友正在访问" << building->m_BedRoom << endl;
}
void test01()
{
goodGay gg;
gg.visit();
}
int main(){
test01();
system("pause");
return 0;
}
3)成员函数做友元
class Building;
class goodGay
{
public:
goodGay();
void visit(); //只让visit函数作为Building的好朋友,可以发访问Building中私有内容
void visit2();
private:
Building *building;
};
class Building
{
//告诉编译器 goodGay类中的visit成员函数 是Building好朋友,可以访问私有内容
**friend void GoodGay::visit();**
public:
Building();
public:
string m_SittingRoom; //客厅
private:
string m_BedRoom;//卧室
};
Building::Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}
goodGay::goodGay()
{
building = new Building;
}
void goodGay::visit()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
cout << "好基友正在访问" << building->m_BedRoom << endl;
}
void goodGay::visit2()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
//cout << "好基友正在访问" << building->m_BedRoom << endl;
}
void test01()
{
goodGay gg;
gg.visit();
}
int main(){
test01();
system("pause");
return 0;
}