c++访问修饰符 protected, private, public
C++ 类成员未声明访问修饰符时默认为private
C++ 值未初始化是默认为0 或者NULL 即’\0’ 空字符。
C++ 字符串常量末尾自动插入 ‘\0’null 字符来作为结尾 主要是为了兼容c
构造方法 在“:”后 成员变量(形式参数)完成赋值
C::C( double a, double b, double c): X(a), Y(b), Z(c)
{
....
}
使用类的对象在创建新的对象。新的对象的定义应该是具有不同的内存
编译器会自行定义一个拷贝构造,如果有指针并且动态分配(先 new 指针分配内存再赋值的)动态分配指针内存 时需要在析构时delete 指针 释放内存
classname (const classname &obj) {
// 构造函数的主体
}
函数形参使用对象在赋值时同样调用了拷贝构造方法,在函数结束时调用了析构方法,
声明在类中,不属于类的成员方法(调用不是类的对象, 而是别的调用), 可以访问类的所有成员
函数内敛 编译器把函数副本放在每个调用函数的地方,并且函数的定义只能有一行 否则编译器会忽略 inline
隐式存在于 类中,所有成员方法都可以访问this notice 友元不能访问this 因为他不是成员函数
静态成员在所有类的对象上只有一个副本
可以通过 “::” 来在类的外部访问静态对象并且修改值,
静态函数可以直接通过类来调用只需要”::”范围解析就可以访问,但是静态函数只能访问类的静态成员,不能访问其他成员
并且它不能访问this , this 需要确定的对象。
is – a 的关系 让派生类可以拥有父类的一切(private 部分无法访问但是拥有,构造析构 拷贝都没有 , 运算符重载也没有 , 友元也没有)
class derived-class: access-specifier base-class
继承的类型:
c++继承也可以声明声明访问限制符, 同样默认值是private,几乎所有继承都使用public,
以下为继承修饰带来的效果
公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
也就是派生会把基类的方法移动到派生对于的范围下
c++ 支持多继承 以逗号分隔,使用修饰符以及类名来表达
函数签名:包含返回值, 参数类型,函数名称
因此调用一个函数 名称时 会根据传入的参数进入不同的函数
您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
//demo
Box operator+(const Box&);
//return type + “operator” keywords + “运算符”;
一元运算符: 只有一个对象 : – , ++ , - ,!, 对一个对象计算,
二元运算符: 两个对象:二元运算符需要两个参数,下面是二元运算符的实例。我们平常使用的加运算符( + )、减运算符( - )、乘运算符( * )和除运算符( / )都属于二元运算符。就像加(+)运算符。
下面的实例演示了如何重载加运算符( + )。类似地,您也可以尝试重载减运算符( - )和除运算符( / )。
类层次关系: 继承 来实现多态。- 根据实例对象来掉层级对应的方法。
Notice!:c++为静态连接早绑定的面向对象语言,方法在编译时已经绑定好了所以需要virtual关键字来实现。
虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。
纯虚函数 virtual int area() = 0;
拥有纯虚函数的类是无法被实例化的 必须由继承他覆盖纯虚函数的子类实例化
c++ 11 之后加入的关键字 override 可以显示表面该函数是覆盖父类函数的让代码更加可读
如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。纯虚函数是通过在声明中使用 “= 0” 来指定的
了解动态内存在 C++ 中是如何工作的是成为一名合格的 C++ 程序员必不可少的。C++ 程序中的内存分为两个部分:
// 局部变量
栈:在函数内部声明的所有变量都将占用栈内存。
堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
很多时候,您无法提前预知需要多少内存来存储某个定义变量中的特定信息,所需内存的大小需要在运行时才能确定。
栈内存虽然存取非常快捷,但是也是很有限的,不合理使用栈内存会导致栈内存溢出。所以在c++函数声明中经常使用 引用 或者指针来减少栈内存的开销,因为大对象的函数赋值会拷贝对象,开销更多不应该开销的内存
void func(const type& a)
{
// 传入一个对象的引用 即传入了对象本身,不会有任何内存开销
// 同时声明为const防止对象被修改
}
void func(const type* a)
{
//传入一个const 对象的指针
}
//const type* a 与 type* const a的区别
//可以从const修饰的对象看出来 前者修饰type 所以 a指向的对象不可变 后者修饰a 所以a 不可变
在 C++ 中,您可以使用特殊的运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。这种运算符即 new 运算符。
如果您不需要动态分配内存,可以使用 delete 运算符,删除之前由 new 运算符分配的内存
动态申请内存可能返回null 所以需要校验
// 包换了申请内存以及判断非空
if( !(pvalue = new double ))
{
cout << "Error: out of memory." <exit(1);
}
//delete 可以在任意地方调用
delete pvalue;
//对象也是可以用new 来申请内存
//数组的动态内存分配:
char* pvalue = NULL; // 初始化为 null 的指针
pvalue = new char[20]; // 为变量请求内存
delete [] pvalue; // 删除 pvalue 所指向的数组
int ROW = 2;
int COL = 3;
double **pvalue = new double* [ROW]; // 为行分配内存
// 为列分配内存
for(int i = 0; i < COL; i++) {
pvalue[i] = new double[COL];
}
for(int i = 0; i < COL; i++) {
delete[] pvalue[i];
}
delete [] pvalue;
定义了范围,寻找方法的范围, c++ 函数可以不依赖类, namespace 定义
namespace namespace_name {
// 代码声明
}
using 指令向当前文件添加命名空间范围。后续方法都会默认使用该命名范围下的方法。
泛型编程基础
//函数模板 :
template <class type> ret-type func-name(parameter list)
{
// 函数的主体
}
//类模板:
template <class type> class class-name {
.
.
.
}
//#define 宏定义
#define macro-name replacement-text
//简单的文本替换。
//函数宏 函数名 函数体
#define MIN(a,b) (((a)<(b)) ? a : b)
//条件编译
#ifndef NULL
#define NULL 0
#endif
//区间内代码不会编译 所以与被注释同样效果
#if 0
//不进行编译的代码
#endif
````
class="se-preview-section-delimiter">
### c++信号
signal() 函数
C++ 信号处理库提供了 signal 函数,用来捕获突发事件。以下是 signal() 函数的语法:
void (*signal (int sig, void (*func)(int)))(int);
这个函数接收两个参数:第一个参数是一个整数,代表了信号的编号;第二个参数是一个指向信号处理函数的指针。
让我们编写一个简单的 C++ 程序,使用 signal() 函数捕获 SIGINT 信号。不管您想在程序中捕获什么信号,您都必须使用 signal 函数来注册信号,并将其与信号处理程序相关联。看看下面的实例:
c++可以传入函数指针来作为参数
class="se-preview-section-delimiter">
### c++多线程
创建线程
POSIX 线程:
class="se-preview-section-delimiter">