c++中智能指针unique_ptr中get()
bar是一个智能指针。
auto p = bar.get(); 后,bar并非被释放,也就相当于指针p和智能指针bar共同管理一个对象,所以就*p做的一切,都会反应到bar指向的对象上。
this指针
this 只能用在类的内部,通过 this 可以访问类的所有成员,包括 private、protected、public 属性的。
当成员函数的参数和成员变量重名,只能通过 this 区分。如:
class Student{
public:
void setname(char *name);
private:
char *name;
};
void Student::setname(char *name){
this->name = name;
}
结构体构造函数
在C++中除了类中可以有构造函数和析构函数外,结构体中也可以包含构造函数和析构函数,这是因为结构体和类基本雷同,唯一区别是,类中成员变量默认为私有,而结构体中则为公有。注意,C++中的结构体是可以有析构函数和构造函数,而C则不允许。
例子:
class BOX {
BOX(int a) {
b = a;
}
public:
...
private:
...
}
int mian() {
BOX Q(2);
return 0;
}
访问修饰符
一个类可以有多个 public、protected 或 private 标记区域,成员和类的默认访问修饰符是 private。
(1)public修饰的公有成员在程序中类的外部也是可访问的;
(2)protect修饰的保护成员变量或函数与私有成员相似,但protect成员在派生类(即子类)中是可访问的;
(3)private修饰的私有成员变量或函数在类的外部是不可访问的,只有当前类和友元函数可以访问private成员。
访问修饰符在继承的特点
(1)public 继承:基类 public,protected ,private修饰的成员的访问属性在派生类中分别变成:public, protected, private(333)
(2)protected 继承:基类 public,protected,private修饰的成员的访问属性在派生类中分别变成:protected, protected, private(221)
(3)private 继承:基类 public,protected,private修饰的成员的访问属性在派生类中分别变成:private, private, private(111)
但无论哪种继承方式,有两点都没有改变:
(1)private 成员只能被本类成员(类内)和友元访问,不能被派生类访问;
(2)protected 成员可以被派生类访问。
构造函数,析构函数和拷贝构造函数
(1)类的构造函数是类的一种特殊成员函数,它会在每次创建类的新对象时执行。
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。
(2)类的析构函数会在每次删除所创建的对象时执行。
析构函数的名称与类的名称也是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
如果程序里没有构造函数和析构函数,编译器在编译的时候会自动生成构造函数和析构函数
(3)拷贝构造函数是一种特殊的构造函数,它在创建对象时,创建一个与一个对象一某一样的新对象。拷贝构造函数通常用于:
通过使用另一个同类型的对象来初始化新创建的对象。
复制对象把它作为参数传递给函数。
复制对象,并从函数返回这个对象。
重载函数和重载运算符
C++ 允许在同一作用域中的某个函数和运算符进行多个定义,分别称为函数重载和运算符重载。
重载是指在该作用域中声明了已经具有相同名称的函数或者方法,但他们的参数和定义不同,编译器以此进行区分,选择最合适的重载函数或重载运算符的过程,称为重载决策。
(1)重载函数
如下例子:
#include <iostream>
using namespace std;
class printData
{
public:
void print(int i) {
cout << "整数为: " << i << endl;
}
//声明并定义了具有相同函数名称的函数(重载函数)
void print(double f) {
cout << "浮点数为: " << f << endl;
}
};
int main(void)
{
printData pd;
// 输出整数
pd.print(5);
// 输出浮点数
pd.print(500.263);
return 0;
}
结果如下:
整数为: 5
浮点数为: 500.263
(2)重载运算符
运算符重载函数的格式:
函数类型 opretor 运算符名称 (形参表){
对运算符的重载处理
}
多态
同一操作(行为/功能) 作用于不同对象, 可以产生不同的执行结果。简单来说就是一种接口,多种形态(接口就是方法),程序在运行时才决定调用哪个函数。
实现方式:C++多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数。而子类重新定义父类的做法称为**(重载/重写/重定义)**,只有重载/重写/重定义了虚函数的才能算作是体现了C++多态。
用法:最常见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。
note:如果子类想要实例化对象,那么子类就必须实现纯虚函数,否则会报错。
重载、重写、重定义的区别:
静态多态和动态多态:
静态多态:子类重新定义父类使用了重载的方式,编译时确定使用哪个子类的函数;
动态多态:子类重新定义父类使用了重写的方式,运行时确定使用哪个子类的函数。
数据抽象,数据封装和接口(抽象类)
数据抽象:
数据成员(变量)需要放进类的私有部分里面,这样对数据成员的操作代码都会被限制在类的代码里面,出了问题方便改。跟写C的时候尽量把对结构体的数据成员操作的代码规范成函数是一个道理,出了问题方便进行定位和修改。
数据抽象是一种仅向用户暴露接口而把具体的实现细节隐藏起来的机制。
数据封装:
是一种把数据和操作数据的函数捆绑在一起的机制。
接口(抽象类):
如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。纯虚函数是通过在声明中使用 “= 0” 来指定的,如下:
virtual double getVolume() = 0;
设计抽象类(通常称为 ABC)的目的,是为了给其他类提供一个可以继承的适当的基类。抽象类不能直接被用于实例化对象,它只能作为接口使用,在实例化对象之前必须在子类中重写纯虚函数。如果试图实例化一个抽象类的对象,会导致编译错误。