c++ primer plus
1.运算符重载
1.1普通运算符的重载
TIme time::reset(const time &t) const{} 这是一种写法,主要是定义在类里面的。
complex complex::operator+(const complex &A) const 这是需要定义在类的定义外,我们需要对其在类里面申请友元。
friend complex operator+(const complex &A, const complex &B);
在类里面定义的可以只要一个输入,但是在外面定义的,必须要有两个输入。
1.2++和–的重载
stopwatch operator++(); //++i,前置形式
stopwatch operator++(int); //i++,后置形式
stopwatch stopwatch::operator++(){
return run();
}
stopwatch stopwatch::operator++(int n){
stopwatch s = *this;
run();
return s;
}
1.3()强制类型转换的重载
class Complex
{
double real, imag;
public:
Complex(double r = 0, double i = 0) :real®, imag(i) {};
operator double() { return real; } //重载强制类型转换运算符 double
};
这里是把complex转换为double类型。
1.4 new 和 delete
new 和delete的重载可以是全局也可以是类成员函数。
1.5 下标[]
class Array{
public:
Array(int length = 0);
~Array();
public:
int & operator[](int i);
const int & operator[](int i) const;
public:
int length() const { return m_length; }
void display() const;
private:
int m_length; //数组长度
int *m_p; //指向数组内存的指针
};
Array::Array(int length): m_length(length){
if(length == 0){
m_p = NULL;
}else{
m_p = new int[length];
}
}
int& Array::operator[](int i){
return m_p[i];
}
const int & Array::operator[](int i) const{
return m_p[i];
}
1.6 << >> 在这个地方只重载为单一的,则只能一个一个的>>.
istream & operator>>(istream &in, complex &A){
in >> A.m_real >> A.m_imag;
return in;
}
ostream & operator<<(ostream &out, complex &A){
out << A.m_real <<" + “<< A.m_imag <<” i ";
return out;
}
http://c.biancheng.net/cplus/operator/
类型很多,需要牢记。
2.构造函数/析构函数
Stock::stock(string &co,long double){}
Stock::~stock(string %a,int b){}
不要试图使用类成员函数名作为形参名
如果重载了类的构造函数,我们不能直接使用默认的设置或者创建对象。即不能:stock stock1;
如果想使用上述表达的形式,我们必须要对构造函数的参数赋初始值。或者是通过重载函数来构造另外一个构造函数。
3.友元
http://c.biancheng.net/cplus/operator/
都在这里,总结的非常好。
3.1继承的优先级
基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如,当继承方式为 protected 时,那么基类成员在派生类中的访问权限最高也为 protected,高于 protected 的会降级为 protected,但低于 protected 不会升级。再如,当继承方式为 public 时,那么基类成员在派生类中的访问权限将保持不变。
也就是说,继承方式中的 public、protected、private 是用来指明基类成员在派生类中的最高访问权限的。
在派生类中访问基类 private 成员的唯一方法就是借助基类的非 private 成员函数,如果基类没有非 private 成员函数,那么该成员在派生类中将无法访问。
赋值的本质是将现有的数据写入已分配好的内存中,对象的内存只包含了成员变量,所以对象之间的赋值是成员变量的赋值,成员函数不存在赋值问题。
这种转换关系是不可逆的,只能用派生类对象给基类对象赋值,而不能用基类对象给派生类对象赋值。
3.2 继承的实例
#include
using namespace std;
//基类 Pelple
class People{
public:
void setname(char *name);
void setage(int age);
char *getname();
int getage();
private:
char *m_name;
int m_age;
};
void People::setname(char name){ m_name = name; }
void People::setage(int age){ m_age = age; }
char People::getname(){ return m_name; }
int People::getage(){ return m_age;}
//派生类 Student
class Student: public People{
public:
void setscore(float score);
float getscore();
private:
float m_score;
};
void Student::setscore(float score){ m_score = score; }
float Student::getscore(){ return m_score; }
int main(){
Student stu;
stu.setname(“小明”);
stu.setage(16);
stu.setscore(95.5f);
cout<<stu.getname()<<"的年龄是 “<<stu.getage()<<”,成绩是 "<<stu.getscore()<<endl;
return 0;
}
3.3继承的构造函数
这种矛盾在C++继承中是普遍存在的,解决这个问题的思路是:在派生类的构造函数中调用基类的构造函数。
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
People(name, age)就是调用基类的构造函数,并将 name 和 age 作为实参传递给它,m_score(score)是派生类的参数初始化表,它们之间以逗号,隔开。
也可以将基类构造函数的调用放在参数初始化表后面:
Student::Student(char *name, int age, float score): m_score(score), People(name, age){ }
但是不管它们的顺序如何,派生类构造函数总是先调用基类构造函数再执行其他代码(包括参数初始化表以及函数体中的代码),总体上看和下面的形式类似:
Student::Student(char *name, int age, float score){
People(name, age);
m_score = score;
}
当然这段代码只是为了方便大家理解,实际上这样写是错误的,因为基类构造函数不会被继承,不能当做普通的成员函数来调用。换句话说,只能将基类构造函数的调用放在函数头部,不能放在函数体中。
//python 继承会要调用父类的构造函数。
另外,函数头部是对基类构造函数的调用,而不是声明,所以括号里的参数是实参,它们不但可以是派生类构造函数参数列表中的参数,还可以是局部变量、常量等,例如:
纯文本复制
Student::Student(char *name, int age, float score): People(“小明”, 16), m_score(score){ }
3.4继承的析构函数
创建派生类对象时,构造函数的执行顺序和继承顺序相同,即先执行基类构造函数,再执行派生类构造函数。
而销毁派生类对象时,析构函数的执行顺序和继承顺序相反,即先执行派生类析构函数,再执行基类析构函数。
https://blog.csdn.net/u013925378/article/details/82762830
排序方法的总结
https://www.cnblogs.com/itsharehome/p/11058010.html
linux ext2
https://blog.csdn.net/gongjiwei/article/details/82025142
windows 环境变量
https://baijiahao.baidu.com/s?id=1652500747054512497&wfr=spider&for=pc
正则表达式
https://deerchao.cn/tutorials/regex/regex.htm
mysql
简明教程
https://www.jianshu.com/p/77781d62120e
https://blog.csdn.net/kellyred/article/details/106176445
https://www.cnblogs.com/laumians-notes/p/9069498.html
账户相关操作:
https://www.cnblogs.com/sos-blue/p/6852945.html
以及pymysql
基础的pymysql:https://www.cnblogs.com/smartsmile-yxh/p/11988644.html
https://www.cnblogs.com/wt11/p/6141225.html
pymysql连接 inner join on https://www.runoob.com/mysql/mysql-join.html
sql为了区别变量和关键字,可以对关键字加反引号,即~下面的符号。
CREATE TABLE bilibili_user_info
(
id
int(10) unsigned AUTO_INCREMENT,
mid
int(20) unsigned ,
name
varchar(45) ,
sex
varchar(45) ,
rankrecord
int(20) unsigned ,
face
varchar(200) ,
regtime
varchar(45) ,
spacesta
varchar(45) ,
birthday
varchar(45) ,
sign
varchar(300) ,
level
varchar(45) ,
OfficialVerifyType
varchar(45) ,
OfficialVerifyDesc
varchar(100) ,
vipType
varchar(45) ,
vipStatus
varchar(45) ,
toutu
varchar(200) ,
toutuId
int(20) unsigned ,
coins
int(20) unsigned ,
following
int(20) unsigned ,
fans
int(20) unsigned ,
archiveview
int(20) unsigned ,
article
int(20) unsigned ,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
mysql数据类型 https://www.runoob.com/mysql/mysql-data-types.html
MySQL创建数据表 https://www.runoob.com/mysql/mysql-create-tables.html
mysql分组 https://www.runoob.com/mysql/mysql-group-by-statement.html
SET NAMES utf8; 防止乱码
is null/is not null /<=> 不等于 https://www.runoob.com/mysql/mysql-null.html
外键 补充
[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, …)
REFERENCES tbl_name (index_col_name, …)
[ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
[ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
https://blog.csdn.net/qq_34306360/article/details/79717682
事务
https://www.runoob.com/mysql/mysql-transaction.html
网络原理自学完整。
sql相关面试题
https://blog.csdn.net/ThinkWon/article/details/104778621?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
整理的非常全面
mysql B树,索引
https://blog.csdn.net/guanghuichenshao/article/details/81948438
乐观锁
https://zhuanlan.zhihu.com/p/137818729
https://blog.csdn.net/caisongcheng_good/article/details/79916873
innodb四大特性
https://www.cnblogs.com/zhs0/p/10528520.html
设计模式
https://www.runoob.com/design-pattern/design-pattern-intro.html
C++虚函数
https://www.jianshu.com/p/ca7e87e640a4
拥有 Virtual 关键字的函数称之为虚函数
虚函数的作用是实现动态绑定的,也就是说程序在运行的时候动态的的选择合适的成员函数
那么,有哪些函数可以成为虚函数?那些函数不可以成为虚函数?
要成为虚函数必须满足两点,一就是这个函数依赖于对象调用,因为虚函数就是依赖于对象调用,因为虚函数是存在于虚函数表中,有一个虚函数指针指向这个虚表,所以要调用虚函数,必须通过虚函数指针,而虚函数指针是存在于对象中的。二就是这个函数必须可以取地址,因为我们的虚函数表中存放的是虚函数函数入口地址,如果函数不能寻址,就不能成为虚函数。
所以呢,这些函数不能成为虚函数;
1.内联函数:我们都知道内联函数只是在函数调用点将其展开,它不能产生函数符号,所以不能往虚表中存放,自然就不能成为虚函数。
2.静态函数:定义为静态函数的函数,这个函数只和类有关系,它不完全依赖于对象调用,所以也不能成为虚函数。
3.构造函数:都知道只有当调用了构造函数,这个对象才能产生,如果把构造函数写成虚函数,这时候我们的对象就没有办法生 成。更别说用对象去调用了。所以构造函数不能成为虚函数。
那些函数可以成为虚函数呢?
普通的成员方法是可以成为虚函数的
还有析构函数,因为析构函数是为了释放对象的,所以之前我们的对象已经生成,而且析构函数可以取地址,所以可以成为虚函数。
那么,什么情况下,析构函数必须定义为虚函数。
当我们定义了一个基类指针,然后在堆上new了一个派生类的对象,让这个指针指向堆上开辟的这块内存。
Base *p = new Derive(10);
delete p;
如果基类的析构函数没有写成虚函数,delete这个基类指针,就不能释放掉堆上的派生类对象。因为delete p会调用基类的析构,你觉得调用基类的析构函数会释放掉派生类的对象吗?当然是不可能的。所以我们就要把基类的析构函数写成虚函数。写成虚函数后,当delete的时候,先会去基类调用析构函数,一看基类的析构函数是虚函数,就会自动的到派生类中调用派生类的析构函数。这时候派生类的对象就能释放了。
#include <iostream>
using namespace std;
class A {
public:
A() {
ver = 'A';
}
void print() const {
cout << "The A version is: " << ver << endl;
}
protected:
char ver;
};
class D1 :public A {
public:
D1(int number) {
info = number;
ver = '1';
}
void print() const {
cout << "The D1 info: " << info << " version: " << ver << endl;
}
private:
int info;
};
class D2 :public A {
public:
D2(int number) {
info = number;
}
void print() const {
cout << "The D2 info: " << info << " version: " << ver << endl;
}
private:
int info;
};
int main() {
A a;
D1 d1(4);
D2 d2(100);
A *p = &a;
p->print();
p = &d1;
p->print();
p = &d2;
p->print();
system("pause");
return 0;
}
输出结果为:
The A version is: A
The A version is: 1
The A version is: A
导致这里出现这样的原因是指针是基类指针,这样的指针只会调用基类的方法,其实在这种情况下我们可以使用派生类对象的指针来获取派生类的方法。但是有没有办法能够让编译器自己识别?
#include <iostream>
using namespace std;
class A {
public:
A() {
ver = 'A';
}
virtual void print() const {
cout << "The A version is: " << ver << endl;
}
protected:
char ver;
};
class D1 :public A {
public:
D1(int number) {
info = number;
ver = '1';
}
void print() const {
cout << "The D1 info: " << info << " version: " << ver << endl;
}
private:
int info;
};
class D2 :public A {
public:
D2(int number) {
info = number;
}
void print() const {
cout << "The D2 info: " << info << " version: " << ver << endl;
}
private:
int info;
};
int main() {
A a;
D1 d1(4);
D2 d2(100);
A *p = &a;
p->print();
p = &d1;
p->print();
p = &d2;
p->print();
system("pause");
return 0;
}
The A version is: A
The D1 info: 4 version: 1
The D2 info: 100 version: A
可以看到,将基类方法改成虚函数,那么就会动态绑定,在运行时才决定调用哪个函数。
补充:上面函数后面有个const修饰,表示该成员函数不能修改任何成员变量,除非成员变量用mutable修饰。const修饰的成员函数也不能调用非const修饰的成员函数,因为可能引起成员变量的改变。
mutalbe的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量(mutable只能由于修饰类的非静态数据成员),将永远处于可变的状态,即使在一个const函数中。
C++中const、volatile、mutable的用法
https://www.cnblogs.com/xkfz007/articles/2419540.html
https://blog.csdn.net/kuweicai/article/details/82779648#t29
面试题 16:访问基类的私有虚函数
写出以下程序的输出结果:
#include <iostream.h> class A
{
virtual void g()
{
cout << "A::g" << endl;
}
private:
virtual void f()
{
cout << "A::f" << endl;
}
};
class B : public A
{
void g()
{
cout << "B::g" << endl;
}
virtual void h()
{
cout << "B::h" << endl;
}
};
typedef void( *Fun )( void ); void main()
{
B b;
Fun pFun;
for(int i = 0 ; i < 3; i++)
{
pFun = ( Fun )*( ( int* ) * ( int* )( &b ) + i );
pFun();
}
}
输出结果:
B::g
A::f
B::h
注意:本题主要考察了面试者对虚函数的理解程度。一个对虚函数不了解的人很难正确的做出本题。
在学习面向对象的多态性时一定要深刻理解虚函数表的工作原理。
https://blog.csdn.net/cwj649956781/article/details/17055885
https://wenku.baidu.com/view/a61dc401eff9aef8941e0634.html
STL部分 – 智能指针 shared-ptr unique_ptr
https://blog.csdn.net/shaosunrise/article/details/85228823?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase
https://blog.csdn.net/shaosunrise/article/details/85158249
关于delete和delete[]
对于基本类型,数组和单个变量是没有区别的.
对于自定义类型,delete只会删除第一个元素,需要传入自定义的删除算法,中间使用delete[]。
https://blog.csdn.net/shaosunrise/article/details/85158249
部分原理讲解在在这里
https://blog.csdn.net/u014796694/article/details/81218033
STL其他容器的模型的简介
https://blog.csdn.net/weixin_42223149/article/details/88684339
https://blog.csdn.net/sarahzhang0104/article/details/92829886?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-3
AVL树
https://blog.csdn.net/qq_29590355/article/details/89324655
https://www.cnblogs.com/lanhaicode/p/11298338.html
https://www.cnblogs.com/lanhaicode/p/11321243.html
红黑树
https://blog.csdn.net/wejboke626/article/details/84971437
https://www.cnblogs.com/qingergege/p/7351659.html
B树 B+树
https://www.cnblogs.com/nullzx/p/8729425.html
JSON
https://www.runoob.com/python3/python3-json.html
错误与异常‘:
https://www.runoob.com/python3/python3-errors-execptions.html
mysql check:
https://blog.csdn.net/weixin_43054397/article/details/93020765
https://blog.csdn.net/GodLordGee/article/details/90752827
类型转换
https://www.py.cn/jishu/jichu/13420.html