好记性不如烂笔头
本文将记录在学习C++ 过程中的一些知识小点。以便查询和面试准备
const
成员函数后加const
编译器会自动给每一个函数加一个this指针。在一个类的函数后面加上const后,就表明这个函数是不能改变类的成员变量的(加了mutable修饰的除外)。实际上,也就是对这个this指针加上了const修饰
class test
{
public:
test(int a=10):aa(a){}
~test(){}
int getA() const
{
aa++,
bb++;
return aa
}
private:
int aa;
mutable int bb;
};
int main()
{
test t(100);
int cc = t.getA(); //会报错,因为不能对成员变量aa 进行左值操作
};
protected
经常看见protected类型的成员变量或者接口,为什么会有这个关键字
- 需求
假如基类Base中有一个成员b,设计要求隐藏这个成员,但是在派生类的成员函数中又经常访问到。如何设计呢?
- 目的
出于隐藏的目的不能设为公有public,但又需要在派生类的成员函数中经常访问到的基类成员,将它们设置为保护成员,既能起到隐藏的目的,又避免了派生类成员函数要访问它们时只能间接访问所带来的麻烦。
- 表现形式
保护成员扩大的访问范围表现在:基类的保护成员可以在派生类的成员函数中被访问。
class A{
public:
A(int x,int y):x(x),y(y){}
protected:
void print()
{cout<<"x point:"<<x<<endl<<"y point:"<<y<<endl;}
private:
int x;
int y;
};
class B:public A{
public:
B(int x,int y,int z):A(x,y),z(z){}
void output()
{print();cout<<"z point:"<<z<<endl;}//此处调用了基类的protected成员print(),这是合法的。
private:
int z;
};
int main()
{
A a(2,3);
B b(4,5,6);
//a.print();//这是不合法的,基类对象不能调用保护属性成员
//b.print();//不合法
b.output(); //调用public成员,合法;该成员函数内部调用了保护成员print()
return 0;
}
成员函数指针
class A{
public:
void Func(int){
std::cout << "I am in A" << std::endl;
}
};
要取得Func函数的指针,必须这么做:
void (A::*pFunc)(int) = &A::Func;
:: 符号, 该符号是一个特殊的操作符,表示pFunc是一个指针,指向类A的成员函数。 获取成员函数的地址不能通过类对象来获取,必须像上面的那样,通过类名来获取,而且要加上取地址操作符(&)
- 调用方法 1
A a;
(a.*pFunc)(10);
- 调用方法 2
A *pa = &a;
(pa->*pFunc)(11);
Lamda表达式
[capature list](param list)->return type{ function body};
std::function
- 普通函数
#include <iostream>
#include "functional"
using namespace std;
std::function<void(int a)> fun1;
std::function<void(string str)> fun2;
std::function<string(int a, int b)> fun3;
void normal_func(int a)
{
cout<<"normal function "<<endl;
}
static void normal_static_func(string str)
{
cout<<"normal static fun:"<<str<<endl;
}
auto lambda = [](int a, int b)->string{
int c = a+b;
cout<<"a+b="<<c<<endl;
return "lambda fun";
};
int main()
{
cout << "Hello World!" << endl;
fun1 = normal_func;
fun1(1);
fun2 = normal_static_func;
fun2("2");
fun3 = lambda;
cout<<fun3(2,3)<<endl;
SAY_FUN fp = Person::Say;
fp();
system("pause");
return 0;
}
Hello World!
normal function
normal static fun:2
a+b=5
lambda fun
- 类成员静态和非静态函数使用
#include <iostream>
#include "functional"
using namespace std;
class Person{
public:
void SayHello()
{
cout<<"SayHello()"<<endl;
}
static void Say()
{
cout<<"Say()"<<endl;
}
};
typedef std::function<void()> SAY_FUN ;
typedef std::function<void(Person)> SAY_FUN2;
int main()
{
cout << "Hello World!" << endl;
SAY_FUN fp = Person::Say;
fp();
Person per;
//类中的非静态成员函数借助bind的做法
fp = std::bind(&Person::SayHello, per);
fp();
//类中的非静态成员函数不借助bind的做法
SAY_FUN2 fp2 = &Person::SayHello;
fp2(per);
system("pause");
return 0;
}
- output
Hello World!
Say()
SayHello()
SayHello()
友元类和有元函数
Friend Classes(友元类)
一个类中的私有成员变量或者函数,在类外是没有办法被访问的。但是,如果我们必须要访问该怎么办呢?这就要用到友元函数或者友元类了。
而友元函数和友元类,就相当于一些受信任的人。我们在原来的类中定义友元函数或者友元类,告诉程序:这些函数可以访问我的私有成员。
C++通过过friend关键字定义友元函数或者友元类。
- 声明
friend class aClass;
class CCar
{
private:
int price;
friend class CDriver; //声明 CDriver 为友元类
};
class CDriver
{
public:
CCar myCar;
void ModifyCar() //改装汽车
{
myCar.price += 1000; //因CDriver是CCar的友元类,故此处可以访问其私有成员
}
};
int main()
{
return 0;
}
#include <iostream>
using namespace std;
class Date {
public:
Date (int year, int month, int day) {
this -> year = year;
this -> month = month;
this -> day = day;
}
friend void p();
private:
int year;
int month;
int day;
};
void p() {
Date birthday(2020, 12, 29);
birthday.year = 2000;
cout << birthday.year << endl;
}
int main()
{
p();
return 0;
}
虚析构函数
为什么需要虚析构函数?简而言之,是为了防止内存泄漏。
那这里的内存泄漏又是怎么产生的呢? 背后的逻辑是什么?
- 产生内存泄漏的原因:
- 派生类的析构函数中有需要回收的内存(这些内存在堆上分配的)
- 在编程过程中采用了基类指针指向派生类对象,如为了实现多态,并且通过基类指针将该对象销毁
就会因为基类的析构函数为非虚析构函数而不触发动态绑定,从而没有调用派生类的析构函数而导致内存泄漏。
(C++中基类的析构函数为什么要用virtual虚析构函数)[https://blog.csdn.net/iicy266/article/details/11906457?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&utm_relevant_index=1]