C++学习笔记

面向对象开发的四大特性:
封装、抽象、继承、多态

封装:
封装是面向对象编程中的把数据和操作数据的函数绑定在一起
这样可以避免受到外界的干扰和误用,从而确保安全
C++通过创建类来支持封装和数据隐藏。
通常情况下,我们都会设置类成员状态为私有,
除非我们真的需要将其暴露,这样才能保证良好的封装性

抽象:
数据抽象是指,只向外界提供关键信息,并隐藏其后台的实现细节
C++类为数据抽象提供了可能

C++接口(抽象类)
接口描述了类的行为和功能,而不需要完成类的特定实现
抽象类与数据抽象互不混淆
如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。
//纯虚函数
virtual double getVolume()=0;
设计抽象类的目的,是为了给其他类提供一个可以继承的适当的基类。
抽象类不能用于实例化对象,他只能作为接口使用。
如果试图实例化一个抽象类的对象,会导致编译错误。
派生类也是如此
如果没有在派生类中重写纯虚函数,就尝试实例化该类的对象,会导致编译错误。
可用于实例化对象的类被称为具体类。

继承:
面向对象程序设计中最重要的一个概念就是继承
继承允许我们依据另一个类来定义一个类。

多态:
{
C++中的多态有很多种表现形式:虚函数,模板,抽象类
虚函数是基类中使用关键字virtual声明的函数。
在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,
这种操作被称为动态链接,或后期绑定。

模板(template)
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
模板是创建泛型类和函数的蓝图或公式
STL中,容器,迭代器,算法都使用了模板,都是泛型编程的例子。
每个容器都有一个单一的定义,比如向量,我们可以定义许多不同类型的向量,比如
vector
vector

函数模板:
template
void
{
//函数的主体
}
例如:

template
T Max(T const&a,T const&b)
{
return a>b?a:b;
}

类模板:
可以定义相同的操作,拥有不同数据类型的成员属性。
通常使用template来声明。告诉编译器,碰到T不要报错,表示一种泛型
//类模板
//Stack实现一种先进后出的数据结构,是一个模板类
template
class Stack
{
private:
vector elems;//元素
public:
//入栈
void push(const T &data);

//出栈
void pop();

T Top() const;

//成员函数,不能修改对象内任何元素
bool empty() const
{
	return elems.empty();//如果为空则反
}

};
template
void Stack::push(const T &data)
{
elems.push_back(data);
}

template
void Stack::pop()
{
if (elems.empty())
{
cout << “栈为空” << endl;
throw out_of_range(“Stack<>::pop(): empty stack”);
}
//删除最后一个元素
elems.pop_back();
}

template
T Stack::Top() const
{
if (elems.empty())
{
cout << “栈为空” << endl;
throw out_of_range(“Stack<>::pop(): empty stack”);
}
//返回最后一个元素的副本
return elems.back();

}

抽象:
数据抽象是一种仅向用户暴露接口而把具体的实现细节隐藏起来的机制

strcpy函数:
char *strcpy(char *strDest,const char *strSource)
{
assert((strDest!=NULL)&&(strSource!=NULL));
char * strRet = strDest;
while((strDest++= StrSource++)!=’\0’);
return strRet;
//返回strDest的原始值使函数能够支持链式表达式,
//增加了函数的“附加值”。
//同样功能的函数,如果能合理地提高的可用性,自然就更加理想。
}

malloc——向系统申请分配指定size个字节的内存空间,返回类型为void*类型。
需强行转换为实际类型的指针。
eg:int *p; p= (int *) malloc ( sizeof (int) );
malloc后面必须跟着free()释放内存

c的free和c++的delete的区别:
首先free对应的是malloc;delete对应的是new;
free用来释放malloc出来动态内存,delete用来释放new出来的动态内存空间。
free只有一个参数(需要释放内存块的首地址)

new和malloc内部的实现方式区别:
new的功能是在堆区新建一个对象,并返回该对象的指针。
new分配的内存块通常与常规变量声明分配的内存块不同。
常规变量的值都存储在被称为栈(stack)的内存区,
而new从被称为堆(heap)或自由存储区(free store)的内存区域分配内存

所谓【新建对象】的意思就是,将调用该类的构造函数,
因为如果不构造的话,就不能称之为一个对象

malloc只是机械的分配一块内存,
如果用malloc在堆区创建一个对象的话,是不会调用构造函数的。

用 delete 去释放一个堆区的对象,会调用该对象的析构函数。
用 free 去释放一个堆区的对象,不会调用该对象的析构函数。

共同点:
它们都是只把指针所指向的内存释放掉了,并没有把指针本身干掉。
在free和delete之后,都需要把指向清理内存的指针置为空,即p=NULL,
否则指针指向的内存空间虽然释放了,但是指针p的值还是记录的那块地址,
该地址对应的内存是垃圾,p就成了“野指针”。

C++ 中有大量的函数用来操作以 null 结尾的字符串:
strcpy(s1, s2);复制字符串 s2 到字符串 s1。
strcat(s1, s2);连接字符串 s2 到字符串 s1 的末尾。
strlen(s1);返回字符串 s1 的长度。
strcmp(s1, s2);如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0。
strchr(s1, ch);返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
strstr(s1, s2);返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
以上函数不能用于C++中string类的对象

C++const总结
如果这个参数是做输入的
(通常做输入的在函数内部只需要读取这个参数而不会需要更改它)
就在指针前面加const来修饰;如果函数形参是指针变量并且还没加const,
那么就表示这个参数是用来做输出型参数的。

不涉及指针的话
const int a;和int const a;是没有去别的

const 修饰指针变量有以下三种情况:
1、const修饰指针指向的内容,则内容不可改变;
const int *p = 8; //指针指向的内容8不可改变
2、const修饰指针,则指针为不可改变指针;
int *const p = &a;// 指针p指向的内存地址不能被改变,但内容可以改变
3、const修饰指针和指针指向的内容,则指针和指针指向的内容都为不可变量。
const int *const p = &a;//p指向的内容和指向的地址都已经固定,不可改变

(总结:坐定值,右定向,const修饰不变量)

const参数传递和函数返回值
A:值传递,一般这种情况不需要const修饰,因为函数会自动产生临时变量复制实参值。
B:当const参数为指针时,可以防止指针被意外篡改。
C:自定义类型的参数传递,需要临时对象复制参数,对于临时对象的构造,
需要调用构造函数,比较浪费时间,因此我们采取const外加引用传递的方法。

当const在函数名前面的时候修饰的是函数返回值,在函数名后面表示是常成员函数
该函数不能修改对象内的任何成员,只能发生读操作,不能发生写操作。

C++引用
1、不存在空引用。引用必须连接到一块合法的内存。
2、一旦引用被初始化为一个对象,就不能被指向到另一个对象。
3、引用必须在创建时被初始化。

C++支持把引用作为参数传给函数,这比传一般的参数更安全。
C++之所以增加引用类型,主要是把它作为函数参数,以扩充函数传递数据的功能。

1、把引用作为参数
C++提供了传递变量的引用。
形参是引用变量,和实参是一个变量,
调用函数时,形参(引用变量)指向实参变量单元。
这种通过形参引用可以改变实参的值。

2、把引用作为返回值
当函数返回一个引用时,则返回一个指向返回值的隐式指针。
这样,函数就可以放在赋值语句的左边。
注意:当返回一个引用时,要注意被引用的对象不能超出作用域。
所以返回一个对局部变量的引用是不合法的
但是可以返回一个对静态变量的引用。

int& func()
{
int q;
//return q;在编译时发生错误
static int x;
return x;//安全,x在函数作用域外依然是有效的
}

类&对象:
公有(public)成员在程序中类的外部是可访问的。
私有(private)成员变量或函数在类的外部是不可访问的,甚至是不可查看的。
保护(protected)成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。

C++拷贝构造函数:
使用之前创造的同类型的对象来初始化新建的对象,常用于:
1、通过使用另一个同类型的对象来初始化新创建的对象。
2、复制对象把它作为参数传递给函数。
3、复制对象,并从函数返回这个对象。

如果在类中没有定义拷贝构造函数,编译器会自行定义一个。
如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。
拷贝构造函数的常见形式:
classname (const classname &obj) {
// 构造函数的主体
}
浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,
默认拷贝构造函数执行的也是浅拷贝
大多情况下“浅拷贝”已经能很好地工作了,
但是一旦对象存在了动态成员,那么浅拷贝就会出问题了

深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,
经深拷贝后的指针是指向两个不同地址的指针。

深拷贝和浅拷贝可以简单理解为:
如果一个类拥有资源,当这个类的对象发生复制过程的时候,
资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。

继承:
class A{
int a;
}

class B : private A{

}

在类中如果继承时不显示声明是 private,protected,public 继承,则默认是 private 继承,
在 struct 中默认 public 继承。

继承中的特点
有public, protected, private三种继承方式,它们相应地改变了基类成员的访问属性。

1.public 继承:基类 public 成员,protected 成员,private 成员的访问属性
在派生类中分别变成:public, protected, private

2.protected 继承:基类 public 成员,protected 成员,private 成员的访问属性
在派生类中分别变成:protected, protected, private

3.private 继承:基类 public 成员,protected 成员,private 成员的访问属性
在派生类中分别变成:private, private, private

一个派生类继承了所有的基类方法,但下列情况除外:
1、基类的构造函数、析构函数和拷贝构造函数
2、基类的重载运算符
3、基类的友元函数

C++重载运算符
模板:
Box operator+(const Box&);

C++多态:

C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数;

形成多态必须具备三个条件:
1、必须存在继承关系;
2、继承关系必须有同名虚函数(其中虚函数是在基类中使用关键字Virtual声明的函数,
在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数);
3、存在基类类型的指针或者引用,通过该指针或引用调用虚函数;

虚函数 是在基类中使用关键字 virtual 声明的函数。

纯虚函数:
virtual int area() = 0;
=0告诉编译器,函数没有主体,上面的虚函数是纯虚函数。
纯虚函数一定没有定义,纯虚函数用来规范派生类的行为,即接口
包含纯虚函数的类是抽象类,抽象类不能定义实例,
但可以声明指向实现该抽象类的具体类的指针或引用。

C++接口(抽象类)
如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。
纯虚函数在通过声明中使用=0来指定
抽象类b不能用于实例化对象,只能作为接口使用。

C++动态内存
栈:在函数内部声明的所有变量都将占用栈内存
堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存
释放内存delete

C++模板:
模板是泛型编程的基础,泛型编程即以一种独立与任何特定类型的方式编写代码。

template
T& num(T &a, T &b)
{
return a > b ? a : b;
}

C++标准库:
标准库函数:这个库是由通用的、独立的、不属于任何类的函数组成的。
面向对象类库:这个库是类及其相关函数的集合。

C++ 编译器会在初始化数组时,自动把 ‘\0’ 放在字符串的末尾。

static 存储类指示编译器在程序的生命周期内保持局部变量的存在,
而不需要在每次它进入和离开作用域时进行创建和销毁。
因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。

assert()断言:
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行
assert()的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销
每个assert只检验一个条件
在函数开始处检验传入参数的合法性

C++ 标准库没有提供所谓的日期类型。
C++ 继承了 C 语言用于日期和时间操作的结构和函数。
#include

// 把 now 转换为字符串形式
char* dt = ctime(&now);

// 把 now 转换为 tm 结构
tm *gmtm = gmtime(&now);
dt = asctime(gmtm);

String类和标准模板库(STL):
智能指针模板类
//编写String的构造函数、析构函数和赋值函数

class String
{
private:
char m_data;
public:
//基本函数
String(const char
str=NULL);//简单构造函数
String(const String &other);//拷贝构造函数
~String(void);//析构函数
//成员函数运算符重载,其实一般需要返回自身对象的
String & operator=(const String &other);//重载=运算符

//友元函数重载运算符
friend String operator+(const String&other_1,const String &other_2);//重载+运算符
friend ostream &operator<<(ostream&out,const String &other);//重载<<输出符
friend istream &operator>>(istream *in,String &other);//重载>>输入符

}

String::String(const char* str=NULL)//普通构造函数
{
if(str==NULL)
{
m_data=new char[1];
*m_data=’\0’;
}
else
{
int len=strlen(str);
m_data=new char[len+1];
strcpy(m_data,str);
}
}

String::String(const String &other)//拷贝构造函数
{
int len=strlen(other.m_data);
m_data=new char[len+1];
strcpy(,m_data,other.data);
}

String::~String(void)
{
delete []m_data;
}

String &String::operator=(const Sting &other) //重构运算符(=)
{
if(this==&other)
{
return *this;
}
delete []m_data;//先释放之前的空间
int len=strlen(other.m_data);
m_data=new char[len+1];
strcpy(,m_data,other.data);
return *this;
}

String operator+(const String &other_1,const String &other_2)
{

String mid_str;	
int len=strlen(other_1.m_data)+strlen(other_2.m_data);
delete []mid_str.m_data;
mid_str.m_data=new char[len+1];
strcpy(mid_str.m_data,other_1.m_data);
strcat(mid_str.m_data,other_2.m_data);
return mid_str;

}

C++STL组件:
容器(Containers)
算法(Algorithms)
迭代器(iterators)

vector
由于运算符[]被重载,因此创建vector对象后,可以使用通常的数组表示法来访问各个元素。
size()返回容器中元素数目
swap()交换两个容器的内容
begin()返回一个指向容器第一个元素的迭代器
end()返回一个表示超过容器尾的迭代器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值