【C/C++】- 程序设计基础

目录

一、C语言知识

2. extern(外部)

3. 头文件写法

二、C++

(一)一些说明

1.内联函数

2. 函数重载

3. 引用(别名)

4. string类

 5. 字符串的定义和引用方法

(二)类和对象

类的示例程序:

1.成员对象和封闭类

2.友元(这是我朋友,可以用我的东西)

3.动态内存分配

(三)继承和派生(子类继承、增改父类的成员)

继承示例程序:

1.继承和派生(代码的重用性)

2. 继承关系和复合关系

3. 派生类覆盖基类成员

4. 公有继承的赋值兼容规则

(四)多态和虚函数(基类用指针调用子类的成员)

多态示例程序:

 1. 虚函数和多态

2. 多态的实现原理

3. 纯虚函数、抽象类、虚析构函数

(五)运算符重载、模板(万物归一)

重载和模板示例程序:

1.运算符重载

2. 重载类型转换运算符

(六)输入输出、文件读写

1. 输入输出

 2.流插入运算符和流提取运算符的重载

2. 文件读写

(七)标准模板库STL


一、C语言知识

1.自增自减

a=i++是先赋值,然后再自增;a=++i是先自增,后赋值。

2. extern(外部)

  • 个文件内声明extern a,表示把全局变量a的作用域扩展到当前。
  • 多个文件之间:只在源文件C中定义了全局变量int a,那么在文件B中声明extern  int a,就可以用到a的值了。
  • 替代方法1:在源文件C内定义全局变量int a,在其头文件H中声明extern int a,那么其他文件B里只要include过,就可以用前者的变量或函数
  • 替代方法2:在源文件C中定义了Li,又在头文件H内声明了struct student Li,那么其他文件B里只要include过,就可以用前者的变量或函数
  • 定义变量或函数时默认缺省了extern,否则用static加以限制作用域。

3. 头文件写法

#ifndef _add_H_
#define _add_H_

int add(int x, int y);

#endif 

4. include

哪里需要就可以在哪里include,同名的头文件中include的库,源文件中不必重复include。

二、C++

(一)一些说明

1.内联函数

在函数调用处直接嵌入函数体的函数称为内联函数,内联函数一般不使用。

2. 函数重载

3. 引用(别名)

int &r=n; 

//引用n  相当于r的别名,对n的修改等于对r的修改,除非加上const。

4. string类

string模板类:typedef basic_string<char> string

子串:

rfind //反方向寻找

还有:erase、replace、insert、c_str

 5. 字符串的定义和引用方法

(19条消息) C++中字符串的三种定义和引用方法_嗯哼丶是你呀的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/ZhanChiFei21580/article/details/129210822?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22129210822%22%2C%22source%22%3A%22ZhanChiFei21580%22%7D

(二)类和对象

类的示例程序:

头文件:

#ifndef _MYCLASS_H_
#define _MYCLASS_H_


class A {
public:
	//成员函数
	void show();
	double getscore() const; //常成员函数,不能修改成员变量
	void setage(int age);  //设置成员变量的值
	void setscore(double score);  //设置成员变量的值

	//友元函数(说明这是外来函数,可以使用本类中的所有成员。
	friend double adds(A* adult, double extra);

	//构造函数
	A(); //无参构造函数
	A(const char* name, int sys, const char* school = "北大");
	A(const char* name,int sys, int age = 25, double score = 99); //构造函数重载
	A(int sys=100);

		//成员变量
	const int m_sys;    //常成员变量,值定义后不能被修改,只能通过初始化参数列表的构造函数初始化

private:
	const char* m_name;
	int m_age;  
	double m_score;
	const char* m_school;   //普通的成员变量只能通过实例化的对象来访问
	static int m_number;//静态成员变量,定义要在类外。通过类和对象都能访问。
	                        //静态成员函数只能访问同类的静态成员变量
};


#endif

 源文件:

#include "myClass.h"
#include <iostream>
using namespace std;

int A::m_number = 0;//静态成员变量的初始化必须在类外

//******///1构造函数


A::A(const char* name,int sys, int age, double score): m_name(name), m_sys(sys) {//构造函数的重载
	m_age = age;
	m_score = score;
	m_number++;
	m_school = "无";
}

A::A(const char* name, int sys, const char* school) :m_name(name), m_age(25), m_score(99), m_school(school) , m_sys(sys) {
	//构造函数初始化列表
	m_number++;
}

A::A(int sys) : m_sys(sys) {  //只能通过初始化参数列表表来初始化常成员变量
	m_name = "小明";
	m_age = 23;
	m_score = 95;
	m_number++;//每输入一个信息,计数一次
	m_school = "无";
}


//**************//2成员函数
void A::show() {
	cout << m_name << "的年龄是" << m_age <<  ",学校是" << m_school << endl;
	cout << "现在有" << m_number << "个人"<<endl;
}

double A::getscore () const
{
	return m_score;//可读不可写
}

void A::setage(int age) {
	m_age = age;
}

void A::setscore(double score) {
	m_score = score;
}

double adds(A* adult, double extra)
{
	return adult->A::m_score + extra;
}


//**************//3成员函数

主函数:

#include <iostream>
#include "myClass.h"
using namespace std;


int main()
{
	cout << "你好" << endl;
//在栈上创建对象
	A peer0(100);  //调用无参构造函数
	peer0.show();
	A peer2("小王",100,26);   //后面的参数使用构造函数的默认参数
	A peer3("小王", 100,26,99.6); 
	A peer4("小王",100, "南航");   //构造函数的重载
	peer4.show();

	A* p = new A(100); //在堆上创建动态对象
	p->setage(29); //使用成员函数给私有的成员变量赋值
	p->show();
	cout<<p->getscore()<<endl; //使用常成员函数读取私有成员变量

	//通过友元函数加分
	cout << adds(p, 62.3) << endl;

//在堆上动态创建对象
	
	system("pause");
	return 0;
}

 运行结果:

 

1.成员对象和封闭类

封闭类:有成员对象的类

声明外部可用用extern

构造函数:名字和类的名字相同,初始化的作用。

复制构造函数:用一个对象去初始化同类的另一个对象。

2.友元(这是我朋友,可以用我的东西)

(1)友元函数:一个类的友元函数可以访问该类的私有成员

  • 形式(是一个声明、过渡)
  • 在一个类里说明一个非成员函数是该类的友元函数,则在外部的非成员函数中可以访问那个类的私有成员。
  • 可以将一个类的成员函数(包括构造、析构函数)说明为另一个类的友元:

在类A中说明类B的一个成员函数为类A的友元,则在类B的那个成员函数中,可以直接访问类A的私有成员。

(2)友元类:如果A是B的友元类,那个A的成员函数可以访问B的私有成员:

  •  在类A中声明B是类A的友元类,则在类B中可以访问类A的私有成员

(友元类之间的关系不能传递,不能继承)

3.动态内存分配

        p=new T

         p=new T[n]  p是一个指针,T为类型名

        delete p

(三)继承和派生(子类继承、增改父类的成员)

继承示例程序:

头文件 myInherit.h

#ifndef _MYINHERIT_H_
#define _MYINHERIT_H_

class A
{
public:
	A(int len);
	void show();
	int adds(int ext);

protected:
	int m_len;
};

class B :public A {
public:
	B(int len, int num);// 
	void show(double a, double b); 
	//只要函数名字相同,就会修改继承的成员函数
private:
	int m_num;
};

#endif

源文件 myInherit.cpp

#include "myInherit.h"
#include <iostream>
using namespace std;

//*******************A
A::A(int len):m_len(len) {}

void A::show()
{
	cout << "A的len为" << m_len << endl;
}

int A::adds(int ext)
{
	return m_len+ext;
}


//******************B
B::B(int len, int num) : A(len), m_num(num){}  //调用基类A的构造函数

void B::show(double a, double b)
{
	cout << "B的len为" << m_len ;
	cout << ",B两数之和为" << a + b << endl;
}

主文件 main.cpp

#include <iostream>
#include "myInherit.h"
using namespace std;

int main()
{

	A* p = new A(20);
	p->show();
	B* q = new B(30, 0);
	q->show(3,4);  //用的派生类的成员函数

	p = q;   //基类指针指向派生类,只能改变成员变量的值,不能使用成员函数
	p->show(); 

	cout << endl;
	A xxl(1);
	xxl.show();
	B yyl(2, 3);
	yyl.show(7,12);

	xxl = yyl;  //派生类向基类赋值,不能反过来,因为少值不够赋给多值
	xxl.show();  //基类的私有变量m_len是派生类的值,但是调用的函数却是基类的。

	//总结:编译器通过指针来访问成员变量,指针指向哪个对象就使用哪个对象的数据;
	// 编译器通过指针的类型来访问成员函数,指针属于哪个类的类型就使用哪个类的函数。
	//除非虚函数
	system("pause");
	return 0;
}

运行结果:

1.继承和派生(代码的重用性)

继承:在定义一个新的类B时,如果该类与某个已有的类A相似(指的是B拥有A的全部特点),那么就可以把A作为一个基类,而吧B作为基类的一个派生类(也称子类)。

  • 派生类是通过对基类进行修改和扩充得到的。在派生类中,可以扩充新的成员变量和成员函数。派生类一经定义后,可以独立使用,不依赖于基类。
  • 派生类名y拥有基类的全部成员函数和成员变量,在派生类的各个成员函数中,不能访问基类中的private成员。

写法

class 派生类名:public基类名

{

};

内存空间:在派生类对象中,包含着基类对象,而且基类对象的存储位置位于派生类对象新增的成员变量之前。

2. 继承关系和复合关系

类之间的两种关系:

(1)是:一个B对象也是一个A对象

(2)有:类C中“有”成员变量k,k是类D的对象,则C和D是复合关系,D对象是C对象的固有属性或组成部分。

3. 派生类覆盖基类成员

覆盖:派生类可以定义一个和基类成员同名的成员,叫做覆盖。在派生类中访问这类成员时,缺省的情况是访问派生类中定义的成员。要在派生类中访问由基类定义的同名成员时,要使用作用域符号::。

类的保护成员:

类除了公有成员和私有成员外,还有保护成员。派生类的成员函数可以访问当前对象的基类的保护成员,但是私有成员不能。

派生类的构造函数:

在创建派生类的对象时,需要调用基类的构造函数:初始化派生类对象中从基类继承的成员。在执行一个派生类的构造函数之前,总是先执行基类的构造函数。

调用时有显示和隐式(默认构造函数)

4. 公有继承的赋值兼容规则

直接基类与间接基类:

在声明派生类时,只需要列出它的直接基类。

构造函数从最顶层的基类开始执行。

(四)多态和虚函数(基类用指针调用子类的成员)

多态示例程序:

什么时候用?首先看成员函数所在的类是否会作为基类。然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该将它声明为虚函数。

头文件 myVirtual.h

#ifndef _MYVIRTUAL_H_
#define _MYVIRTUAL_H_

class A
{
public:
	A(int len);
	virtual void show(double a,double b); //基类虚函数必须有关键字
	

protected:
	int m_len;
};

class B :public A {

public:
	B(int len, int num);// 
	void show(double a, double b);  //虚函数的原型必须一模一样
	

private:
	int m_num;
};




#endif

源文件 myVirtual.cpp

#include "myVirtual.h"
#include <iostream>
using namespace std;



//*******************A
A::A(int len):m_len(len) {}

void A::show(double a, double b)
{
	cout << "A的len为" << m_len <<"和为" <<a+b<< endl;
}




//******************B
B::B(int len, int num) : A(len), m_num(num){}  //调用基类A的构造函数

void B::show(double a, double b)
{
	cout << "B的len为" << m_len <<"乘积为"<<a * b<<endl;
}

主文件 main.cpp

#include <iostream>
#include "myVirtual.h"
using namespace std;

int main()
{

	A* p = new A(20);
	p->show(55,66);
	B* q = new B(30, 0);
	q->show(44,77);  //用的派生类的成员函数

	p = q;   //基类指针指向派生类,只会改变指针指向,不会改变其对象的值
	//或者简单的A*p=new B(30,0);
	p->show(55,66); 
	
	system("pause");
	return 0;
}

运行结果:

 1. 虚函数和多态

class base{

          virtual int get();

};

int base::get(){}//写函数体时不用

多态:

  • 派生类的指针可以赋给基类指针。通过基类指针调用基类和派生类中的同名虚函数时,若该指针指向一个基类的对象,那么被调用的是基类的虚函数;若指针指向一个派生类的对象,那么被调用的是派生类的虚函数。这种机制叫做“多态”
  • 派生类的对象可以赋给基类引用。通过基类引用调用基类和派生类中的同名虚函数时,若该引用引用的是一个基类的对象,那么被调用的是基类的虚函数,派生类亦然。

除了构造函数和析构函数,在派生类中和基类中与虚函数同名同参数表的函数,不加virtual也自动成为虚函数。

2. 多态的实现原理

动态连编——编译时不确定调用的是基类的还是派生类的函数,运行时才能确定。

虚函数表。放在前几个字节中

3. 纯虚函数、抽象类、虚析构函数

一般有虚函数时,把析构函数也写成虚函数。

纯虚函数(没有函数体的):

virtual void p()=0;

(五)运算符重载、模板(万物归一)

重载和模板示例程序:

1.运算符重载

(1)实质是函数的重载

返回值类型 operator 运算符(形参表)

{

……

}

例:

class complex{

public:

double real,image;

complex operato-(const complex &c);//作为成员函数

};

complex operator+(const complex &a, const complex &b){

return complex (a.real+b.real, a.image+b.image);//返回一个临时对象

}//作为  全局函数

int main()

{

complex a(4,4),b(1,1),c;

c=a+b;//a+b等价于c=operator+(a,b);

cout<<(a-b).real;//a-b等价于a.operator-(b)

(2)重载为成员函数时,参数个数为运算符目数(操作数)减一,重载为普通函数时,参数个数为运算符目数。

(3)赋值运算符重载=

  • a=b的返回值是对a的引用,即&a。
  • 只能重载于成员函数

(4)运算符重载为友元函数

2. 重载类型转换运算符

(六)输入输出、文件读写

1. 输入输出

https://blog.csdn.net/ZhanChiFei21580/article/details/129454865icon-default.png?t=N7T8https://blog.csdn.net/ZhanChiFei21580/article/details/129454865

 2.流插入运算符和流提取运算符的重载

cout<<5<<”this”;//为什么能够成立?

本质上的函数调用形式是:cout.operator<<(5).operator<<(“this”)

   cout是在iostream中定义的,是ostream类的对象,<<发生了重载

怎么重载cout<<5?

等价于cont.operator<<(5)

  void ostream::operator<<(int n)

{……//输出n的代码

return;

}

怎么重载cout<<”this”?

等价于cout.operator<<(“this”);

ostream&ostream::operator<<(int n)   //返回值为引用,还是返回cout

{……//输出n的代码

return *this;

}

2. 文件读写

文件读写示例程序:

 

(七)标准模板库STL

  1. 容器是一个与数组类似的单元,可以存储若干个值。
  2. 算法使完成特定任务(如对数组进行排序或在链表中查找特定值)的处方。
  3. 迭代器能够用来遍历容器的对象,与能够遍历数组的指针类似,是广义指针。
  4. 函数对象是类似于函数的对象,可以是类对象或函数指针(包括函数名,因为函数名被用作指针)。
  5. STL使得能够构造各种容器(数组、队列、链表),以及执行各种操作(搜索、排序、随机排列)。

(19条消息) 【C/C++】- STL(ing)_嗯哼丶是你呀的博客-CSDN博客_下列选项中,哪一项不是迭代器。 a. 输入迭代器 b. 前向迭代器 c. 双向迭代器icon-default.png?t=N7T8https://blog.csdn.net/ZhanChiFei21580/article/details/120998768

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁荣生长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值