Authur:SYK
Date:2023-3-2
introduction:本文==适合已经有c语言经验的读者,主要目的是快速上手c++。至于c++面向对象的部分本文只做简要概述。想要深入的读者可以自行查阅有关知识点的资料==。有错误可以指出来。
参考文献:
C++ 教程 | 菜鸟教程 (runoob.com)
(10条消息) 如何从C快速过渡到C++_迷亭1213的博客-CSDN博客
C标准库的头文件xx.h基本上变成了cxx
例如
输出:cout <<
c中 printf("hello");
c++中 cout<< "hello"
输入:cin >>
c中
int x;
scanf("%d",&x);
c++中
cin>> x;
使用命名空间 using namespace std(命名空间的名字)
为什么开始学c++的时候,都要以
#include
using namespace std;
为开头。
因为在调用 cin cout 的时候,实际上是调用 std:cin std:cout.这里因为使用了命名空间,所以就省略了。
endl 换行符
cout << endl
定义引用变量时必须指明其引用的是哪个变量,且不能再指向其他变量
int a = 3;
int &r = a;
&r就代表a的地址。r++相当于a++;
#include
using namespace std;
void swap(int &x, int &y) //X就是a,y就是b,没有产生新的内存块
{
int t = x;
x = y;
y = t;
}
int main()
{
int a = 3, b = 4;
cout << a << '\t' << b << endl;
swap(a, b);
cout << a << '\t' << b << endl;
}
默认形参
int find(a=1){
return a
}
类似于java
,python
当调用这个函数没有传参的时候,就会调用默认值。
函数重载
int find(int a){
return a+1;
}
int find(int a,int b){
return a+b;
}
当函数名相同的时候,传参不同或者返回类型不同都会造成函数的重载。
模板参数==可以自动推断类型,为避免歧义,建议使用时还是加上<类型>==
别称:泛型
template //每一个函数模板都需要加这个
T add(T x, T y)
{
return x + y;
}
#include
#include
using namespace std;
template
T add(T x, T y)
{
return x + y;
}
int main()
{
区别:------
cout << add(5, 3) << endl; //自动推断类型
cout << add(5, 7.8) << endl; //歧义性
cout << add("hello", " world") << endl;
}
string s = "hello", s2 = "world"
常用方法:
int a=s.size() //取大小
s=s.substr(1,3) //取第1~3位的字符,返回字符串
int a=s.find("orl") //查找字符串,返回所在下标
s.insert(3,"ABCD") //在下标3前插入字符串
s.insert(3,4,'w') //在下标3前插入4个w
s1.swap(s2) //交换s1,s2的内容
s1.append(s2) //添加s2的内容到s1:s1="123",s2="abc",->s1="123abc"
s1.append(s2); // s1 = "123abc"
s1.append(s2, 1, 2); // s1 = "123bc"
s1.append(3, 'K'); // s1 = "123KKK"
s1.append("ABCDE", 2, 3); // s1 = "123CDE",添加 "ABCDE" 的子串(2, 3)
s=s.replace(2,3,"aa") //用aa替换原来字符串的第2-3位,返回字符串
s=to_string(a) //把数值类型转化为string
int a=stoi(s1) //把string转化为数值类型int
float a=stof(s1) //把string转化为数值类型flloat
s1.assign(s2) //用s2给s1赋值
s1.assign(s2,2,3) //用s2的第2~3位给s1赋值
s1.assign(10,'c') //用10个c给s1赋值
可以用==运算符” + “、” [] “(下标运算符),处理string==
在C++中,加入了vector的类,可以随时改变数组的大小。
vector::push_back(x) //在容器最后一个位置插入元素x
vector::pop_back() //删除最后一个元素
vector::size() //返回元素个数
vector::capacity() //返回空间大小
vector::resize(n) //重新分配成员个数为n
vector::reserve(n) //重新分配空间大小为n
vector::clear() //清空容器内容,但空间没改变
vector::begin() //返回初始地址
vector::end() //返回结尾地址
vector::erase()//删除元素或⼀段序列
iterator erase(iterator position);
iterator erase(iterator first, iterator last);
vector::insert()//插⼊新的元素
iterator insert(iterator position, const T &x); //v.insert(v.begin()+1,3)在第1位前插入3
void insert(iterator position, size_type n, const T &x);
void insert(iterator position, InputIterator first, InputIterator last);
//第⼀个函数,在迭代器指定的位置前插⼊值为x的元素
//第⼆个函数,在迭代器指定的位置前插⼊n个值为x的元素
//第三个函数,在迭代器指定的位置前插⼊另外⼀个容器的⼀段序列迭代器first到last若插⼊新的元素后总得元素个数⼤于capacity,则重新分配空间
#include
#include
using namespace std;
int main()
{
vector v = {7, 5, 16, 8};
//push_back(),最后添加一个元素
v.push_back(25);
v.push_back(13);
//成员函数size()、下标运算符[]
for (int i = 0; i < v.size(); i++)
cout << v[i] << '\t';
cout << '\n';
v.insert(v.begin()+1, 9); //插入不能用下标
v.pop_back();
for (int i = 0; i < v.size(); i++)
cout << v[i] << '\t';
cout << '\n';
v.resize(2);
for (int i = 0; i < v.size(); i++)
cout << v[i] << '\t';
cout << '\n';
}
#include
#include
#include
using namespace std;
int main()
{
vector a = {1, 2, 3};
cout << "first" << a.capacity();
a.push_back(3);
a.push_back(4);
a.push_back(5);
cout << "second" << a.capacity();
return 0;
}
- 指针变量就是存储指针(地址)的变量,如Type *P; //P是存储 ”Type类型变量的地址“ 的变量
- 可以通过取内容运算符*得到一个指针变量指向的变量,如 *P就是P指向的那个变量
#include ;
using namespace std;
int main()
{
int a = 1; // 作为test
int *p = &a;
cout << p << "\t" << &a << endl;
cout << *p << "\t" << a << endl;
int *q = p;
cout << *p << "\t" << *q << endl;
return 0;
}
new
可以代替malloc
, 且会对对象进行初始化(在类中很有用)int *p = new int; // p在函数的堆栈区,new在全局共享未使用堆存储区
delete可以代替free
delete p; //释放p指向的内存,p本身没有被删掉。
delete[] p; //释放==数组p==指向的内存
/* malloc free realloc 动态内存分配(在c中):new用于申请内存块、delete用于释放内存块 T *p = new T; delete p; T *q = new T[5]; delete[] q; */
// 堆存储区
#include
using namespace std;
int main()
{
int *p = new int;
*p = 3;
cout << p << '\t' << *p << endl;
delete p; //内存泄漏,释放p指向内存
p = new int; //p又指向一个新的内存
*p = 5;
cout << p << '\t' << *p << endl;
delete p;
}
用struct或class关键字定义一个类。定义的类就是一个数据类型。
struct student
{
string name;
double score;
}
class student{
private:
string name;
double score;
public: //接口
void print() {cout << this->name << " " << this->score << endl;}
string get_name() { return name; }
double get_score() { return score; }
void set_name(string n) { name = n; }
void set_score(double s) { score = s; }
};
可以参考这篇文章
【C、C++基础】什么时候用 “.” 什么时候用“->”(3个实例搞懂)_51CTO博客_什么时候用%c
注意:C语言中struct不能定义函数成员,而C++中可以,不过为了区分建议用class,且class有封装特性,自行决定成员公开还是私有,struct默认所有成员公开!!!
学生信息的录入:
#include
using namespace std;
#include
struct Student
{
string name;
double score;
void print();
};
void Student::print()
{
cout << name << " " << score << endl;
}
int main()
{
/* Student stu;
stu.name = "jack";
stu.score = 122323;
stu.print(); */
vector<Student> students;
while (1)
{
Student stu;
cout << "请输入姓名 分数:\n";
cin >> stu.name >> stu.score;
if (stu.score < 0)
{
break;
}
students.push_back(stu);
}
cout << "人员信息为" << endl;
for (int i = 0; i < students.size(); i++)
{
students[i].print();
}
return 0;
}
在c++中,类里面定义的成员函数,实际上==编译器会自动转化为外部函数,并带this指针==。
struct student{
string name;
double score;
//void print(){cout << name << " " << score << endl;}; //函数声明
}
void print(student *this){//函数声明
cout << this->name << " " << this->score << endl;
};
int main(){
student stu;
stu.name = "LI";
stu.score = 88;
stu.print(); // print(&stu) 会转化为指针参数
}
private:私有的,只能通过==类体内==访问
public:公开的,可以在==类体外==访问
protected:受保护的,只能==在类体内访问==或在体外通过成员函数访问—不常用,了解即可。
#include
using namespace std;
class Student
{
public:
void print()
{
cout << this->name << " " << this->age;
}
void setName(string n)
{
this->name = n;
};
void setAge(int x)
{
this->age = x;
};
string getname()
{
return this->name;
};
int getAge()
{
return this->age;
};
private:
string name;
int age;
};
// main function test
int main()
{
Student stu;
stu.setAge(19);
stu.setName("jack");
stu.print();
return -1;
}
- C++在创建一个类对象的时候,会自动调用被称为“构造函数”的成员函数
- 如果没有定义构造函数,那么C++会自动生成一个构造函数:类名函数,且没有返回、没有形参,函数体里什么也不做
class student
{
string name;
double score;
public:
student(string n, double s):name(n),score(s)//用列表初始化
{
cout << "构造函数\n";
}
}
/*等价于*/
class student
{
string name;
double score;
public:
student(string n, double s):
{
name = n;
score = s;
cout << "构造函数\n";
}
}
在创建一个类对象的时候==会自动调用类函数==。
/* 构造函数: 函数名和类名相同且无返回类型的成员函数。 */
#include
#include
using namespace std;
class student
{
string name;
double score;
public:
student(string n, double s)
{ //不是默认构造函数,重载
name = n;
score = s;
cout << "构造函数\n";
}
student()
{
cout << "构造函数" << endl;
}
void print()
{
cout << this->name << " " << this->score << endl;
}
};
int main()
{
student stu("LiPing", 80.5); //在创建一个类对象时会自动调用称为“构造函数”的成员函数
stu.print();
student students[3];
}
构造函数小tips:
- 当构造函数私有化后,就不能调用对象了。类似于构造有条件的三角形。
- 调用构造函数==在声明的时候就会自动调用,java中是通过new==来创建的。
- 列表序列化来声明。
这几个有兴趣的,可以自行查阅资料,这里不深入探讨!
基础:修饰变量
const int a=10;//a不可改
const int* a = &b://整型不可修改,但指针指向可以修改,*a不可改,a可改
int *const a = &b;//整型可修改,指针不可修改,*a可改,a不可改
const int *const p//二者都不可以改
void fun(const int i){}//i不能被修改
在类函数中使用
1.const修饰的函数,不能修改类中的成员变量,这是const修饰函数的基本作用
c++中允许对运算符进行重载,只要==他们的形参列表不一样==,例如输入的cin >>
输出的 cout <<
ostream& operator << (ostream &out, student s)//重载输出流
{
cout << s.name << " "<< s.score << endl;
return out;//引用,返回自身&,不加返回的是一个复制值
}
istream& operator>>(istream &in, student &s) //重载输入流,注意是引用s
{
in >> s.name >> s.score;
return in;
}
还有加法运算符,下标运算符重载。这里不过多赘述!!!
类模板的本质就是让类产生复用,通过泛型机制。前面所讲到的==vector==实际上就是一个类模板。下面我们手动封装一个类模板。
template //创建类模板
class Vector {
T *data;
int capacity;
int n;
public:
Vector(int cap=3) {
data = new T[cap];//开辟的是3倍类型空间
if (data == 0) {
cap = 0; n = 0;
return;
}
capacity = cap;
n = 0;
}
void push_back(T e) {
if (n == capacity) {//空间已经满
cout << "增加容量!\n";
T *p = new T[2 * capacity];
if (p) {
for (int i = 0; i < n; i++)
p[i] = data[i];
delete[] data;
data = p;
capacity = 2*capacity;
}
else {
return;
}
}
data[n] = e;
n++;
}
T operator[](int i) const{
if (i < 0 || i >= n) throw "下标非法!";
return data[i];
}
int size() {
return n;
}
};
int main() {
Vector v; //可以定义任意类型变量
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
v.push_back(7);
for (int i = 0; i < v.size(); i++)
cout << v[i] << '\t';
cout << endl;
}
面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。这部分,如果了解过java的可以看一下语法即可。c++的继承原则:我们几乎不使用 protected 或 private 继承,通常使用 public 继承
class <派生类名>:<继承方式1><基类名1>
{
<派生类类体>
};
#include
using namespace std;
// 基类
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// 派生类
class Rectangle: public Shape
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
Rect.setWidth(5);//通过成员函数访问受保护变量
Rect.setHeight(7);
// 输出对象的面积
cout << "Total area: " << Rect.getArea() << endl;
return 0;
}
c++的多继承机制也成为c++的特色之一。
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};
#include
using namespace std;
// 基类 Shape
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// 基类 PaintCost
class PaintCost
{
public:
int getCost(int area)
{
return area * 70;
}
};
// 派生类
class Rectangle: public Shape, public PaintCost
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
// 输出对象的面积
cout << "Total area: " << Rect.getArea() << endl;
// 输出总花费
cout << "Total paint cost: $" << Rect.getCost(area) << endl;
return 0;
}
关于c++面向对象的特征本文就讲述到这,本文的目的是帮助已经学过c的快速上手c++。以及了解c++的特性。如果大家想要继续深入c++的话,可以阅读c++官方文档或者阅读有关c++的书籍。✌✌✌✌✌