C++笔记
1
推动语言发展的动力是方便和重用
不是只有面向对象语言可以封装,C语言也可以封装,结构体成员是函数指针的时候也是满足的,但是比较麻烦。
2类的定义
类名首字母大写;
方法名首字母小写
Class 类名
{ private:
public:
};
3定义成员函数(调用成员函数时必须指定对象和成员名)
(1)在类中定义成员函数
类中定义的成员函数一般为内联函数,即使没有明确用
inline标示;
在C++中,类定义通常在头文件中,因此这些成员函数
定义也伴随着进入头文件;
(2) 在类之后定义成员函数
C++允许在其它地方定义成员函数;
将类定义和其成员函数定义分开,是目前开发程序的
通常做法。
我们把类定义看成是类的外部接口,类的成员函数定
义看成是类的内部实现。
(3)类成员函数的重载
重载的定义:两个以上的函数,取相同的函数名,但是形参的个数或者类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪个函数。
类的成员函数可以像普通函数一样重载,但是不同类即使有相同的函数名也不算重载。
4成员函数外部定义的格式
返回类型 类名::函数名(参数1,参数2……)
5类的成员的访问
不管怎么继承,父类私有东西是不能访问的
1单个类
类成员可以访问所有;
单个类实例化对象只能访问共有域public
2继承
派生类可以访问父类的public and protected;
Public继承父类的protected and public 在子类中不变;
私有继承,父类的protected and public在子类中转换成私有域;
3保护继承
父类的protected and public全部转换为protected域;
多继承只在c++
成员访问
(1) 如果是私有的,外部全部不能访问;
(2) 如果是公有的,普通对象:对象名.成员
指针对象:对象名->成员
(3) 静态成员或方法
Const不可更改可以直接赋值;公有的,类名::静态成员
(4) 在类中静态成员拥有者是类,静态成员将会只有一个父本
6
构造函数的要求:
(1)函数名必须与类名同名
(2)构造函数可重载;
(3)类实例化后系统会自动调用。
(4)构造函数无返回类型
(5)构造函数不能被用户调用,只能被系统调用;只能在实例化的时候定义;
(6)如果不写构造函数编译器会自动添加一个无參的构造函数。一旦你写了构造 函数,系统将不会给他添加
7
析构函数:释放内存空间
(1)没有返回类型,没有参数,不能随意调用,没有重载。只有在类生命期结束的时候,有系统调用。
(2)析构函数名,就在构造函数名前加上一个“~”,表示“逆构造函数”。
8
堆空间
(1)new:分配堆空间和delete配套使用:释放堆空间。
(2)new一个对象会自动调用构造函数,delete一个对象会自动调用析构函数,new和delete不需要头文件。
(3)从堆中分配对象数组:类名 *ps = new 类名[int n];
(4)释放一个对象数组:delete[]ps;
(5)使用堆空间的原因:直到运行时才能知道需要多少对象空间;不知道对象的生存期到底有多长;知道运行时才知道一个对象需要多少内存空间。
9
构造对象的顺序
(1)局部和静态对象,以声明的顺序构造;
(2)静态对象只被构造一次
(3)所有全局对象都在主函数main()之前被构造
(4)全局对象构造时无特殊顺序
(5)成员以其在类中声明的顺序构造
Class SA{};
SA ();无名对象创建之后就会被释放;
SA h; 执行到最后才会被释放。
对于全局对象,是在main函数执行之前调用构造函数的。
10
赋值格式:
类型 类名::静态名 = a;
静态方法只能访问静态成员,因为他没有this指针。
New兼容malloc的功能。
11
拷贝构造函数:
(1)可用一个对象去构造另一个对象
(2)对象作为函数参数传递时,也要涉及对象的拷贝
(3)class Stu{;;};
(4)Stu fn()(当函数返回一个对象时,要创建一个临时对象以存放返回的对象)
{
Stu ms;//在这里系统调用拷贝构造函数将ms拷贝到新创建的临时对象中
return ms;
}
Int main()
{
//Stu s = fn();//浅拷贝
Stu s;
s = fn();//深拷贝,拷贝的是资源的内容
}
创建的临时对象,在整个创建它们的外部表达式范围内有效,否则无效,也就是说,“s = fn();”这个外部表达式,当fn()返回时产生的临时对象拷贝给s后,临时对象就析构了。
(4)如果类需要析构函数来析构资源,则它也需要一个拷贝函数。
12
引用
C++尽量把引用作为形参
(1)类型&变量名
(2)定义之后必须马上初始化:int m;int &b = m;m和b是等同的,b相当于常量指针一旦确定不能更改。
(3)一旦初始化之后不可更改,而指针是可以的
类中的所有的成员函数都可以访问类中全部的成员变量。
一个类的方法是自身类的有源,有源类的成员方法可以访问私有的变量。
构造函数可以调用成员函数。
引用与指针有什么区别?
1) 引用必须被初始化,指针不必。
2) 引用初始化以后不能被改变,指针可以改变所指的对象。
3) 不存在指向空值的引用,但是存在指向空值的指针。
13
继承(紧耦合)
子类:修饰符(public,private,protected)父类名
定义:
class Shape
{
private:
int m_color;
proteceted:
int m_kind;
public:
void printColor(){printf(“shape color %d\n”,m_color);}
Shape(){printf(“shape class constructed\n”);}
~Shape(){printf(“shape class destroy\n”);}
};
class Circle:public Shape
{
private:
float radius;
public:
Circle(){printf(“circle class constructed\n”);}
~Circle(){printf(“circle class destroy\n”);}
void printAera();
};
子类继承父类的时候:构造函数先完成父类的构造然后完成子类的构造,析构函数则是先完成子类的释放然后在完成父类的释放。如果是private继承的父类的public和protected域 将变成自己的private域。
private,protected:
单个类中:只能是类成员可以访问类的实例化的对象是不可以访问的
public:全部可以访问
一层继承(不论是何种继承,类成员可以直接访问 父类的protected,public)
(1)如果是public
派生类的实例化对象,访问父类的public但不能访问父类的protected
(2)如果是private或者是protected
派生类的实例化对象,不能访问父类的任何域
如果类中含有别的类对象:
本类::本类(参数列表):基类名(参数),对象1(参数),对象2(参数)……
{
本类的初始化工作;
}
14
多继承
virtual继承时需要在父类中添加无參的构造函数。
父类的指针可以指向子类,子类的指针不能指向父类。
15
虚函数的作用:允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
任何一个类都有一个函数入口表,如果是虚的入口地址将会被更改
父类指针指向子类,从而使父类能够访问子类的成员。
虚函数一般不做成内联函数
纯虚函数:拥有纯虚函数的类是不能实例化的,称为抽象类(Java中的接口)。只要有一个纯虚函数就是抽象类,纯虚函数只能定义指针,指向派生类。
入口地址表不在内存中,增加虚函数(个数不限)内存大小增加一个指针大小4个字节。
16 this指针
《深入浅出MFC》中解释:
定义类CRect,定义两个对象rect1、rect2,各有自己的m_color成员变量,但rect1.setcolor和rect2.setcolor却都是通往唯一的CRect::setcolor成员函数,那么CRect::setcolor如何处理不同对象的m_color?答案是由一个隐藏参数,名为this指针。当你调用:
rect1.setcolro(2);
rect2.setcolor(3);
时,编译器实际上为你做出来一下的代码:
CRect::setcolor(2,(CRect*)&rect1);
CRect::setcolor(3,(CRect*)&rect2);
多出来的参数,就是所谓的this指针。
17 指针
1、指针变量可以有空值,即指针变量不指向任何地址。
#include “iostream.h”
int *p; p=NULL;
int *p;
p=0;
2、两指针可以相减,不可相加。若要进行相减运算,则两指针必须指向同一数组,相减结果为相距的数组元素个数
int a[10],*p1,*p2;
p1=a; p2=a+9;
p2-p1 : 9
3、指向同一数组的两个指针变量可以比较大小:p2>p1
18
、有了 malloc/free 为什么还要 new/delete ?
malloc 与 free 是 C++/C 语言的标准库函数,new/delete 是 C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用 malloc/free 无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于 malloc/free。 因此 C++语言需要一个能完成动态内存分配和初始化工作的运算符 new,以及一个能完成清理与释放内存工作的运算符 delete。注意 new/delete 不是库函数。
19 字符串连接1
#include<stdio.h>
class CShape{
private:
int a;
public:
virtual void print(){ printf("CShape= %d\n",this->a);}
virtual void hello() { printf("hello world\n");}
CShape(int x=3) { a=x;}
};
int main()
{
CShape obj(10);
typedef void (*function)(CShape *thiss);
char *ptr=(char *)&obj;
int **p=(int **)ptr;
function fpp=(function)(*(*p));
function fpp1=(function)(*(*p+1));
printf("*******virtaul function pointer**\n");
(*fpp1)(&obj);
(*fpp)(&obj);
printf("*******object call function**\n");
obj.hello();
obj.print();
}
20 字符串连接2
#include <iostream>
using namespace std;
class String
{
public:
String()
{
this->str=NULL;
}
String(char *s)
{
str=(char *)malloc(sizeof(s));
memset(str,0,sizeof(s));
strcpy(str,s);
}
String operator+(const
String& s)
{
String str3;
str3.str=(char *)malloc(sizeof(s.str)+sizeof(this->str));
memset(str3.str,0,sizeof(str3.str));
strcat(str3.str,this->str);
strcat(str3.str,s.str);
return str3;
}
void operator=(const String &s1)
{
if(this->str!=NULL)
free(this->str);
this->str=(char *)malloc(sizeof(s1.str));
strcpy(this->str,s1.str);
//return *this;
}
friend String operator++(String &thiss)
{
int i=0;
while(thiss.str[i]!='\0')
{
thiss.str[i]+=1;
i++;
}
}
void print()
{
cout<<str<<endl;
}
~String()
{
if(str!=NULL)
free(str);
}
private:
char *str;
};
int main()
{
String s1("hello"),s2("world"),s3;
s3 = s1+s2;
s3.print();
return 0;
}