文档库 最新最全的文档下载
当前位置:文档库 › c++知识总结

c++知识总结

第一章类
1.类定义的两种形式
class student
{
public:
protected:
private:
};
struct student
{
public:
protected:
private:
};
类可以定义为空 此时系统为其预留一个字节的空间

2.c++中类与结构体的唯一区别是类定义中默认情况下的成员是private 而结构体中 默认情况下的成员是 public
c与c++的一些区别
(1)结构体中只有数据成员没有成员函数,而类中有数据成员也有成员函数.
(2)结构体中的数据成员都是共有的 可以直接访问,而类中一般数据成员定义为protected 或private ,成员函数定义为 public 此时该类的数据成员只能通过该类的成员函数去访问.
(3)结构体用struct声明 类用class声明 类中的所有虚函数(virtual)由一个指针指向 在c中说明对象的方法是 struct student ST; 在c++中为 student ST;


成员函数的定义一般放在类的外部 定义是必须写明其作用域 函数set 的全名是student::set ::是作用域区分符

endl与\n 不一样 endl执行是要进行强制类型转换


2.内联函数(inline)与宏定义(#define)的区别
使用内联函数节省时间浪费空间
(1)内联数函数,宏是预处理命令
(2)内联是在编译时嵌套在函数中 ,而宏是在预处理时替换
(3)宏定义不具备类型检测,而内联函数会检测
注意:宏定义是一定要加括号 如何加?
内联函数一般1-5句 switch语句不允许用 for语句一般也不用
inline有事可省略
3.函数重载的概念
也就是一次多意了
重载必须满足的两条件(1) 同一个类中 同名的函数 (2)参数列表不同.

在一个类中可以声明多个同名的函数执行不同的操作

4.protected 与private 的区别
在子类的成员函数中可以访问基类的保户成员但不能访问私有成员
若将子类继承基类时用private 声明 孙子类中的成员函数将不能访问基类中的任何成员 若用protected 声明继承时 孙子类中的成员函数可以访问基类的保护成员
class A
{ public:void set(){cout<protected:int i;
private:int j; };
class B:private A
{ public: void set1(){cout<protected: int m;
private: int n; };
class C :public B
{ public: void set2(){cout<protected: int s;
private: int t; };
void main()
{ C c1,c2; c1.set1(); }
4.this 指针
定义每个对象时都有一个this指针指向该对象 所以可以通过this指针使用该对象
在调用成员函数时成员函数除了接受实际给的参数外 还接受了一个对象的地址 这个地址呗一个隐含的形参this所获取

5.类的作用范围
局部类和全局类
其中局部类的成员函数必须在类中定义否则会造成函数嵌套定义
全局类的作用范围是从定义到程序结束
类作用域是指类定义和相应成员函数定义范围 .在该类

范围内,一个雷的成员函数可以无限制的访问该类的任何一个数据成员 对于类外的将受到程序员的控制

6.引用于指针的区别
应用比指针好 能用指针的地方都可以用引用;
(1)引用定义是必须初始化 指针可以不初始化
(2)引用不能为空 而指针可以为空
(3)引用一旦初始化不能改变其指向 但指针可以随时改变其指向
(4)引用自加和指针自加不一样 引用自加是对其实体进行自加
而 指针自加是将指针向前移动
(5)对指针sizeof()和对引用sizeof()结果完全不一样
7.什么函数不能被声明为虚函数
构造函数 拷贝构造函数 静态成员函数 友元函数
8.在c++中默认产生的成员函数有哪些?
构造函数 析构函数 拷贝构造函数 赋值函数
9.虚表的工作原理
有一个虚指针指向一张虚表 一次放虚函数的入口地址 虚表经继承后 如果子类有同名函数 则覆盖以前的 然后 自己的其他虚函数 放在虚表的后面 在调用虚函数的过程也就是虚指针遍历虚表的过程
(10)当成员函数中定义了与类的数据成员同名的变量 该成员变量将被隐藏 ,要用该变量需使用this 指针 如this->m;
如果函数中定义了与类名相同的变量 则类名被隐藏 要定义一个雷对象需加上 class 如 int A ; class A a ;
一个名字不能同时指两种类型 如 class C typedef int C
非类型名不能同名 如student a void a()
类型与非类型不在同一名空间 也即在一个作用域中 一个名字可以声明为一个类型也可以声明为一个非类型 当两者同时登场是 类型名要加前缀
(11)类的封装
首先:数据与算法结合 构成一个不可分割的整体 .其次:在这个整体中一些成员是保护的 他们被有效地屏蔽,以防外界的干扰和误操作 另一些成员是公开的 他们作为接口提供给外界使用.



第二章 构造函数(用于创建对象 无返回值)
缺省构造函数外边定义时 参数不能有默认值 只要有一个参数给默认值
后边的必须给默认值 否则出错 为了全部适应 将构造函数的参数都带默认值
定义对象数组时 必须有默认构造函数(我参构造函数 活缺省构造函数)
在类外定义构造函数时 不能带默认值 (记得加::) (默认值只可以在声明的时候带)
构造函数无返回类型 但可以有无值语句的返回 如 return ;
(1)类与对象的区别
类是所有对象的一个抽象,不占用空间 声明类时不分配空间 只是定义类的大小
对象是类的实体,占用空间 定义对象时要调用构造函数 分配空间 并且初始化 执行函数体
注意: 对象分为有名对象 和无名对象
(2)冒号语法,构造函数的执行流程
冒号语法是

构造对象是进行初始化的 : s(i),t(j)
初始化顺序与定义顺序一致
**常量数据成员和引用都可以作为类的数据成员 但必须要用冒号语法对他们进行初始化
如: private : const int a ; int &a;
构造函数的执行流程 (两阶段)先传参 根据数据成员在类里边的声明顺序
分配空间 并用冒号后边的语句按照数据成员的定义顺序进行初始化 然后进入函数体执行函数体内容
注意:在主函数之前可以执行一段代码(定义全局对象)
全局变量析构在主函数外边进行所以不输出

(3)对象的内存布局
全局变量和静态局部变量在定义时 将位模式清0 局部变量在定义时 分配的内存空间保持原样 故为随机数
(4)析构函数
析构函数的作用是施放对象的空间 (注意:遵循先构造后析构原则)
析构函数不能重载 但析构函数可以实现多态 构造函数可以重载
静态局部变量只初始化一次
对象指针和对象引用
对象指针与对象引用不进行析构因为定义的时候都不调用构造函数分配空间
用malloc 申请空间时不调用构造函数 而new申请空间时调用构造函数
malloc上网年轻的空间用free释放 new申请的空间用delete 释放 new是运算符 是关键字 new 和 malloc 都在堆上分配空间 用free 释放空间的时候也不调用析构函数 但是用 delete 释放空间的时候调用析构函数
(5)构造函数
函数重载指的是 函数名相同但参数列表不同的函数. 不过一般给构造函数的参数带默认值 则可使构造函数的重载合并成一个函数;
构造函数可以被重载,C++根据声明中的参数选择适合的构造函数 .
显式调用一个构造函数将产生一个无名对象
每个类都有构造函数 如果自己定义了构造函数 C++将不在提供给类默认构造函数了 默认构造函数只负责创建对象 不做任何初始化工作
定义对象时不带参数的话后面不能带圆括号
注意: 创建对象与声明函数的区别 Tdate oneday(10); Tdate oneday(int);


(6)static
普通成员 都是给定类的每一个对象的组成部分 static 成员 独立于任何对象而存在 不是类类型对象的组成部分 因为static 数据成员不是任何对象的组成部分 所以他们的使用 方式 对于非 static 数据成员而言是不合法的 非static 数据成员不能用作默认参数, 因为它的值不能独立于所属的对象而使用
使用非static 数据成员 做默认参数 将无法提供对象以获取该成员的值 因而是错误的
static 数据成员 必须在类定义的外部定义(正好一次)不像普通数据成员 static 数据成员 不是通过 类构造函数进行初始化的 而是在定义是进行初始化的

在类定义的时候可以吧该类的对象作为该类

的成员变量 但是该对象必须定义为静态的
因为类是一个抽象的概念,并不是一个实体,并不含有属性值,而只有对象才占有一定的空间,含有明确的属性值.
编译器不能决定文件的连接顺序 所以全局对象的构造是无序的



第三章 堆与拷贝构造函数

(1)c++的内存格局
全局数据区 , 代码区 , 栈区 ,堆区,还有常量存储区(文字常量,字符串常量)
注意:内存泄露
对象的建立是分配空间 , 构造结构 初始化的过程 用new 而不用malloc 的原因
利用malloc ()函数产生的类对象从根本上说不叫类对象的创建
说明利用malloc()函数创建对象可以绕过构造函数
类对象的创建必须是通过调用构造函数产生的
用new分配空间必须要知道对象的类型
构造函数在类外定义是不能带参数 否则会报错
const int get() const{}
成员函数前加const 返回值不能做左值 后面加const 表示函数体中不能改变成员变量的值
new 的一切都是在程序运行时进行的
从堆上分配对象数组时只能调用默认构造函数 不能调用其他任何构造函数 再删除的时候必须带[] 如delete[]ps;
(2)拷贝构造函数(默认拷贝构造函数)
用一个对象构造一个对象时调用拷贝构造
对象作为函数参数传递时也要涉及到拷贝构造函数的调用
在调用函数时 返回对象的时候也调用拷贝构造函数
A a(5);与A a=5;一样 调用构造函数
A b=a;与A b(a);等价 调用拷贝构造
A c ;c=a; 先构造在赋值
拷贝构造函数的参数一般用引用比较直观
A(A&t){}
遇到临时对象和无名对象时系统会自动优化
A b=fn(A(1));
A c=fn(b);
默认拷贝构造函数是完成成员一个一个的拷贝
当成员变量中有指针时不能用浅拷贝必须用深拷贝(及内存申请问题)
(3)临时对象与无名对象
当函数返回对象时要创建临时对象存放返回的对象
一般规定,创建的临时对象 在整个创建他们的外部表达式范围内有效 否则无效。
所以返回的对象不做引用的初始化值
无名对象可以用作实参传给函数 可以拿来拷贝构造一个新对象 也可以初始化一个引用的声明
构造函数用于类型转换
(只会尝试含有一个参数的构造函数 如果有二义性则放弃尝试)

#ifndef sdhgfjdgdhfgd
#define sdhgfjdgdhfgd
防止内容多次编译
#endif
i++不能做左值 ,因为i++产生两个值 ++i可以做左值
若产生临时变量则u能做左值。







第四章 静态成员与友元
(1)静态数据成员
静态成员有静态数据成员和静态成员函数,用static声明 。静态数据成员的空间分配不在类中。
静态数据成员的二次声明一般放在类的实现中 便于移植。进行分配空间和初始化。
二次声明不用static。

对于静态数据未初始化则系统自动按位模式清零。一般在二次声明时进行初始化。
调用静态成员函数时用类名引导 student::number();
静态数据成员是类的一部分 定义时要用类名引导
静态数据成员不依赖于某个特定的对象 保护或私有静态数据成员只可被类的内部访问。
如果是public 的静态数据成员 用类名和对象都可以访问。
成员函数作为对象值操作静态成员返回对象的类型并执行成员函数
如 :s.nextstudent().静态成员 ;
静态数据成员的使用
1)用来保留流动变化对象的个数。
2)作为一个标志 ,指示一个特定的动作是否发生。
3)一个指向一个链表第一个成员或最后一个成员的指针。
this指针指向当前对象。
(2)静态成员函数
静态成员函数可以定义在类中 也不属于任何一个对象。访问类似于public静态数据成员
静态成员函数不能对非静态成员进行默认访问。但可以通过内部定义对象进行访问。
静态成员函数与非静态成员函数的区别是静态成员函数没有this 指针,而非静态成员有一个
指向当前对象的this指针,
(3)友元函数 friend
由原函数的目的是提高效率
为了:
1)避免了频繁调用成员函数,提高效率
2)方便重载操作符的使用
友元函数只能在类里边声明不能进行定义 ,定义时必须在类外进行。
一般与类的成员函数放一起定义。
友元函数的声明位置再类里边没啥区别
一个类的成员函数可以是另一个类的友元
整个类可以是另一个类的友元
友元函数是另一个类的成员函数时 则在函数类型后面要用类型限制。
类名声明不能用于定义类的对象因为这时还没有类的完整声明。


第五章 继承


没有多态的情况 都是先期联编
继承可以使一个类为另一个类提供他的操作和数据结构

单继承和多重继承

理解:虚函数在继承中的应用
派生类继承父类的属性和操作 子类也声明新的属性和操作 剔除了那些不适合于其用途的继承下来的操作

私有成员函数 在派生类中通过声明为public 后可以被访问 private数据成员在派生类中不能被访问 而protected and public

可以被visit

继承权限与访问权限不同 有 public private、protected 、virtual(虚继承)

public 继承 访问时类型的保护性一致
protected 与private 区别在于数据成员在孙子类中是否可以被访问

子类中只能访问 基类的public 和 protected 数据成员

虚继承解决多重继承中的二义性
构造函数中 如果有虚继承则先走虚继承 在走非虚继承

要调用子类的构造函数必须先调用基类的构造函数,因为子类里边永远有一个基类的无名对象,并且作为第一个数据成员
所以先必

须调用基类的构造函数

主意:用冒号语法对无名对象进行初始化
多重继承
class A
{
public void set(){}
};
class B :virtual public A
{
} ;
class C :virtual public A
{
};
class D :public B,public C
{
};
int main()
{
D d;
d.set();//是继承的哪一个?

return 0;

}

主意: 友元 不能被继承 、构造、析构函数也不能被继承 赋值运算符重载也不能被继承
可以用子类的对象去构造基类的对象

静态成员通过继承也可以共享

派生类可以直接访问基类的protected的数据成员 ,甚至在构造时初始化他们 但一般不这么做 而是通过基类的接口去访问他们,初始化也是通过基类的构造函数 ,为了避免基类错误造成的麻烦

在构造一个子类时,完成其基类部分的构造由基类的构造函数去做。

函数参数是对象的引用时 函数执行的过程中不调用构造函数也不调用拷贝构造函数 ,只是将对象传给了引用
函数调用时 子类的对象传给基类的引用时不调用构造函数也不调用拷贝构造函数


虚继承只有一份拷贝

继承中不能把基类对象传给子类 但可以将子类对象传给基类
继承和组合都采用重用,但两种重用在操作上很是不同

能用组合的地方尽量不用继承 因为组合优于继承
C++允许子类重载基类的成员函数

捆绑:把函数调用与函数体连接起来的过程
早捆绑:编译时确定
晚捆绑:运行时确定

C++里的四种多态
(1)重载多态(函数重载 、运算符重载)
(2)参数多态 (函数模板、类模板)
(3)强制多态 强制类型转化 有别于c语言 static_cast const_cast dynamic_cast reinterpret_cast
(4) 包涵多态 (有虚函数的多态)
基类的引用可以接收子类的对象 此时基类中同名的虚函数被子类中的虚函数所覆盖
class A
{
public :
virtual void set(){cout<<"count1"<
}
class B :public A
{
public :
void set(){cout<<"count2"<
}
void fn(A & a)
{
a.set();

}

int main()
{
B b;
fn(b);
return 0;
}
结果为Count2
若不加 vritual 则结果为Count1

多态必备的关系
(1)有两个类 并且是父子关系(继承)
(2) 两个类中必须有同名函数且都是虚函数(覆盖)有些virtual 可以省写
(3)基类的指针或基类的引用指向派生对象

隐藏、覆盖、重载 的区别:
隐藏:(1)同名不同参(继承中)(2)同名同参不是虚函数 (3)不恰当的虚函数

返回引用的时候可以做左值 返回整形的时候不能做左值

类里边的6个默认函数
构造函数 析构函数 拷贝构造函数 赋值函数

如果基类中的虚函数 返回一个基类指针或基类引用,子类中的虚函数返回一个子类指针或子类引用 ,则c++认为是同名虚函数 进行迟后联编

基类指针可以指向子类 但是 子类指

针不可以指向基类

虚函数解决函数调用不清的问题
成员函数 尽可能多的设置为虚函数总是有益的 只会增加一些资源开销
但是:(1)只有类的成员函数才能设置为虚函数 因为虚函数仅适用于类的继承 普通函数不能设置为虚函数 虚表没的地方放
(2)静态成员函数不能使虚函数
(3)inline 函数不能使虚函数 因为内联函数是不能再运行中动态确定其位置的
(4)构造函数不能是虚函数 因为构造时对象还是未定型的空间,只有在构造完成后,对象才能成为一个类的名副其实的实体
(5)析构函数可以是虚函数 而且通常声明为虚函数 为了解决归属权不清问题,防止造成内存不能释放尽

至少包涵一个纯虚的成员函数的类就是抽象类
抽象类的用途是被继承
纯虚函数 virtual void student()= 0;的定义 “=0”表明程序员将不定义该函数 该声明是为派生类而保留的位置
抽象类不可以定义对象,但可以定义指针 和引用

如果无纯虚函数 则基类的指针不可以访问子类的某些虚函数 :理解




getchar() 可以接受 空格、换行、回车 这样的字符 而 cin 不可以接受 空格 、换行、 回车的。
利用模板可以代替由于参数类型不同而造成的函数重载 template
operator 运算符重载的关键字
函数的返回值由函数的类型决定,与函数的调用无关 在函数调用时不识别函数类型

在递归调用函数中必须自己设置 递归函数出口 一般里边有一个if语句















相关文档