c++_day02 学习内容及作业
一、string
string s1="hello czj";//将c风格的字符串转换为c++风格的写法
//拼接字符串
string s2="haoshuai";
string s3=s1+s2;
//字符串遍历,size_t 是无符号整数类型
for(size_t idx=0;idx<s3.size();idx++){
cout<<s3[idx]<<" ";
}
//c++风格的字符串转化为c风格的字符串
const char *pstr=s3.c_str();
//截取子串,其中第一个参数表示起始位置,第二个参数表示截取字节个数
string s4=s3.substr(7,5);
二、类和对象
1、类的定义
/*
对象内部既有属性(数据),又有操作(函数),也就是统一到一块了
类中的成员函数如果只有声明,没有实现,就无法正常工作
*/
void Computer::setBrand(const char *brand)
{
strcpy(_brand, brand);
}
void Computer::setPrice(double price)
{
_price = price;
}
void Computer::print()
{
cout << "品牌:" << _brand << endl
<< "价格:" << _price << endl;
}
//需要加作用域
void test0()
{
c1._price=8888;
//因为_price呗private修饰,无法在类之外直接访问,被限制住了.
}
//在public区域定义的函数称为该类对外提供的接口、功能和服务。

2、class与struct的唯一区别是默认访问权限不一样,class默认为private,struct默认为public的
3、类的无参构造函数
class Point
{
public:
Point(){}//如果不加这个就会报错 因为编译器会提供一个默认的构造函数,与下面这个函数冲突了,因此加上这个就不冲突了。
Point(int ix,int iy){
cout<<"Point(int,int)"<<endl;
_ix=ix;
_iy=iy;
}
void print()
{
cout << "(" << _ix
<< "," << _iy << ")" << endl;
}
private:
int _ix;
int _iy;
};
初始化表达式
class Point
{
public:
Point(int ix=0,int iy=0)
: _ix(ix)
, _iy(iy)//使用这个进行初始化列表
{
cout<<"hello"<<endl;
}
void print()
{
cout << "(" << _ix
<< "," << _iy << ")" << endl;
}
private:
int _ix;
int _iy;
};
1、析构函数
析构函数的调用时机:
1)当栈对象销毁时,自动调用
2)当全局对象销毁时,自动调用
3)当静态对象销毁时,自动调用
4)当堆空间的对象被销毁,执行delete
表达式时,自动调用
2、拷贝构造函数
其调用时机有三种情况:
1)当用一个已经存在的对象初始化另一个新对象时
2)当形参是对象,实参与形参进行结合时
3)当函数的返回值是对象,执行return语句时
3、赋值运算符函数
当类中有指针成员指向堆空间时,必须要重定义。在实现时,要遵循四部曲:
1)自复制
2)回收左操作数的空间
3)进行深拷贝
4)return *this
4、特殊数据成员的初始化
1)const成员函数:必须要在构造函数的初始化表达式中进行初始化
2)引用成员:必须要在构造函数的初始化表达式中进行初始化
3)类对象成员:必须要在构造函数的初始化表达式中进行初始化
4)静态数据成员:在类中声明,但必须要在类之外进行初始化
5、 特殊的成员函数
1)静态成员函数
不能访问非静态的数据成员和非静态的数据成员,只能访问静态的数据成员和成员函数。
2)const成员函数
不能修改类中的数据成员,只能读取数据成员。
加上const关键字后,其实是对隐含的this指针进行了限定, const 类名 * const this
作业
C++Day3
一、选择题
1、在(CE )情况下适宜采用inline
定义内联函数。(多选题)
A、 函数体含有循环语句
B、 函数体含有递归语句
C、 函数代码少、频繁调用
D、 函数代码多、不常调用
E、 需要加快程序执行速度
二、简答题
1、如何判断一段程序是由C 编译器还是由C++编译器编译的?
如果编译器在编译cpp文件,那么_cplusplus就会被定义,如果是一个C文件在被编译,那么_STDC_就会被定义。
2、函数重载的原理是什么?
函数重载:在相同作用域中的多个函数,具有相同的名字而形参表不同。
C++利用name mangling(倾轧)技术,来改名函数名,区分参数不同的同名函数。编译器通过函数名和其参数类型识别重载函数。为了保证类型安全的连接(type-safe linkage),编译器用参数个数和参数类型对每一个函数标识符进行专门编码,这个过程有时称为“名字改编”(name mangling)或“名字修饰”(name decoration)。类型安全的连接使得程序能够调用合适的重载函数并保证了参数传递的一致性。编译器能够检测到并报告连接错误。
3、inline
函数与带参数的宏定义的区别?
(1)内联函数在编译时展开,宏在预编译时展开;
(2)内联函数直接嵌入到目标代码中,宏是简单的做文本替换;
(3)内联函数有类型检测、语法判断等功能,而宏没有;
(4)inline函数是函数,宏不是;
(5)宏定义时要注意书写(参数要括起来)否则容易出现歧义,内联函数不会产生歧义;
4、std::string
与const char *
有什么区别?
std::string &是引用
const char *是指针
所以这两者的区别就是指针和引用的区别.
1、指针是指向一片内存,其内容是内存的地址,而引用就是某块内存的别名。
2、指针有分配内存区域,而引用没有分配内存区域。
3、引用在定义时就被初始化,之后无法改变,但是指针的对象可以改变。
5、一个空类占据的空间有多大?会自动创建哪些函数呢?
#include<bits/stdc++.h>
using namespace std;
class person{
};
int main(){
printf("%ld\n",sizeof(person));
return 0;
}
运行结果:
jing@jing:~/code/2022-3-29$ ./class
1
因此空类占据一个字节
只是声明一个空类,不做任何事情的话,编译器会自动为你生成一个默认构造函数、一个拷贝默认构造函数、一个默认拷贝赋值操作符、一个默认析构函数、取址运算符和一个取址运算符const。这些函数只有在第一次被调用时,才会别编译器创建。所有这些函数都是inline和public的。
6、设A为Test类的对象且赋有初值,则语句Test B(A); 表示什么意思?
相当于将对象A复制给B,也就是调用了默认复制构造函数。
7、什么是拷贝构造函数,其形态是什么,参数可以修改吗?
拷贝构造函数就是用已存在的对象来初始化另一个对象,以及用在函数调用期间于用户定义类型的值传递及返回。
形态是:类名::类名(const 类名&);
它的唯一的一个参数(对象的引用)是不可变的(因为是const型的)
8、什么情况下,会调用拷贝构造函数?
1). 一个对象以值传递的方式传入函数体
2). 一个对象以值传递的方式从函数返回
3). 一个对象需要通过另外一个对象进行初始化
9、什么是赋值运算符函数,其形态是什么?什么情况下需要手动提供赋值运算符函数呢?
拷贝构造函数使用传入对象的值生成一个新的对象的实例,而赋值运算符是将对象的值复制给一个已经存在的实例。
形态是:
返回类型 类名::operator(参数列表){
//...
}
当一个对象被销毁时,另外一个对象也获取不到值,此时就需要手动显式提供赋值运算符函数。
10、浅拷贝与深拷贝区别?
浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,
浅拷贝:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。
深拷贝:在计算机中开辟一块新的内存地址用于存放复制的对象。
三、写出下面程序结果。
1、写出以下程序运行的结果。( )
i=0,k=2
i=0,k=2
#include <iostream>
using std::cout;
using std::endl;
class Sample
{
public:
Sample();
void Display();
private:
int i;
static int k;
};
Sample::Sample()
{
i=0;
k++;
}
void Sample::Display()
{
cout << "i=" << i << ",k=" << k << endl;
}
int Sample::k=0;
int main( )
{
Sample a, b;
a.Display();
b.Display();
return 0;
}
2、设有如下程序结构:
class Box
{
//....
};
int main()
{
Box A,B,C;
}
该程序运行时调用_3_次构造函数;调用 _3_次析构函数。
3、写出下面程序的运行结果()
Constructor1
Constructor2
i=0
i=10
Destructor
Destructor
#include <iostream>
using std::cout;
using std::endl;
class Sample
{
int i;
public:
Sample();
Sample(int val);
void Display();
~Sample();
};
Sample::Sample()
{
cout << "Constructor1" << endl;
i=0;
}
Sample::Sample(int val)
{
cout << "Constructor2" << endl;
i=val;
}
void Sample::Display()
{
cout << "i=" << i << endl;
}
Sample::~Sample()
{
cout << "Destructor" << endl;
}
int main()
{
Sample a, b(10);
a.Display();
b.Display();
return 0;
}
4、设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为?
C c;
void main()
{
A *pa=new A();
B b;
static D d;
delete pa;
}
ABDC
AB不用多说,因为c是全局变量,对它的初始化是在main函数之前,所以析构也是在之后,而D随着main函数的结束也就析构了。
5、写出下面程序的结果:
#include<iostream>
using std::cout;
using std::endl;
int i = 1;
class Test
{
public:
Test()
:_fourth(_third)
,_second(i++)
,_first(i++)
,_third(i++)
{
_third = i;
}
void print()
{
cout << "result : " << _first + _second + _third + _fourth << endl;
}
private:
int _first;
int _second;
int _third;
int &_fourth;//注意:与前面学的引用类比即可
};
int main()
{
Test test;
test.print();
return 0;
}
1+2+4+4=11(fourth复制的third)
6、下列代码在编译时会产生错误的是()
#include <iostream>
using std::cout;
using std::endl;
struct Foo
{
Foo()
{
}
Foo(int)
{
}
void fun()
{
}
};
int main(void)
{
Foo a(10);//语句1
a.fun();//语句2
Foo b();//语句3 =>是一个函数声明,不是对象的创建
b.fun();//语句4
return 0;
}
语句4错误,语句3没有进行对象的创建,此时b依然是一个Foo* 的类型。
四、改错题。
例题1:分析找出以下程序中的错误,说明错误原因,给出修改方案使之能正确运行。
#include <iostream>
using std::cout;
using std::endl;
class Base
{
int a1,a2;
public:
Base(int x1 = 0, x2 = 0);
};
int main()
{
Base data(2,3);
cout << data.a1 << endl;
cout << data.a2 << endl;
return 0;
}
构造函数没有函数体,类的对象不能直接被引用
#include <iostream>
using std::cout;
using std::endl;
class Base
{
int a1,a2;
public:
Base(int x1 = 0, x2 = 0){
a1=x1;
a2=x2;
}
int a11(){return a1;}
int a22(){return a2;}
};
int main()
{
Base data(2,3);
cout << data.a11() << endl;
cout << data.a22() << endl;
return 0;
}
例题2:分析以下程序的错误原因,给出修改方案使之能正确运行。
#include <iostream>
using std::cout;
using std::endl;
class Base
{
float _ix;
float _iy;
public:
Base(float ix,float iy)
{
_ix = ix;
_iy = iy;
}
float gain();
};
Base::float gain()
{
return _iy/_ix;
}
int main()
{
Base base(5.0,10.0);
cout << "The gain is => " << gain() << endl;
return 0;
}
类外函数调用格式有问题,主函数有问题,改正后的:
#include <iostream>
using namespace std;
class Base
{
float _ix,_iy;
public:
Base(float ix,float iy)
{
_ix = ix;
_iy = iy;
}
float gain();
};
float Base:: gain()
{
return _iy/_ix;
}
int main(void)
{
Base error(5.0,10.0);
cout << "The gain is => " << error.gain() << endl;
}
五、编程题。
1、定义一个学生类,其中有3个数据成员:学号、姓名、年龄,以及若干成员函数。同时编写main函数使用这个类,实现对学生数据的赋值和输出。
#include<bits/stdc++.h>
using namespace std;
class Student{
public:
Student(int _id,string _name,int _age){
id=_id;
name=_name;
age=_age;
}
void insert(){
cin>>id>>name>>age;
cout<<endl;
}
void display(){
cout<<"id:"<<id<<endl<<"name:"<<name<<endl<<"age:"<<age<<endl;
}
~Student(){
cout<<"Destructor called"<<endl;
}
private:
int id;//学号
string name;//姓名
int age;//年龄
};
int main(){
Student s1(1001,"shuaige",18);
s1.insert();
s1.display();
return 0;
}
jing@jing:~/code/2022-3-29$ ./student
1002 czj 23
id:1002
name:czj
age:23
Destructor called
2、编写一个程序计算两个给定的长方形的周长和面积。
#include<bits/stdc++.h>
using namespace std;
class Calculate{
double len,wid;
public:
Calculate(double i=0,double j=0){
len=i;
wid=j;
}
Calculate(const Calculate &c){
len=c.len;
wid=c.wid;
}
void area(){
cout<<"the are of it is "<<(len*wid)<<endl;
}
void perimeter(){
cout<<"the perimeter of it is "<<(len+wid)*2<<endl;
}
};
int main(){
double l,w;
cin>>l>>w;
cout<<endl;
Calculate A(l,w);
A.area();
A.perimeter();
cin>>l>>w;
cout<<endl;
Calculate B(l,w);
B.area();
B.perimeter();
return 0;
}
jing@jing:~/code/2022-3-29$ ./area
10 20
the are of it is 200
the perimeter of it is 60
30 40
the are of it is 1200
the perimeter of it is 140
3、编写一个类,实现简单的栈。栈中有以下操作:
> 元素入栈 void push(int);
> 元素出栈 void pop();
> 读出栈顶元素 int top();
> 判断栈空 bool emty();
> 判断栈满 bool full();
如果栈溢出,程序终止。栈的数据成员由存放10个整型数据的数组构成。(可以自己设计入栈出栈的数据)
提示:就是用C++类的方式实现一个栈,然后写出栈的基本操作,入栈、出栈、栈为空、栈为满的函数,以及模拟栈的入栈出栈的操作。
#include <bits/stdc++.h>
using namespace std;
class Stack
{
private:
int *data_; //存放数据
int MaxSize_; //栈的最大空间
int top_; //栈顶
void init_stack()
{
data_ = new int(MaxSize_);
top_ = -1;
} //初始化
public:
Stack()
{
MaxSize_ = 10;
init_stack();
}
Stack(int max_size)
{
MaxSize_=max_size;
init_stack();
}
//判空
bool emty()
{
return (top_ == -1) ? 1 : 0;
}
//判满
bool full()
{
return (top_ >= MaxSize_) ? 1 : 0;
}
//入栈
int push(int x)
{
if (full())
{
return 0;
}
else
{
data_[++top_] = x;
}
return 1;
}
//出栈
int pop(int &x)
{
if (emty())
{
return 0;
}
else
{
x = data_[top_--];
}
return 1;
}
//读栈顶元素
int top()
{
if (emty())
{
return 0;
}
else
{
return data_[top_ - 1];
}
}
};
int main()
{
Stack stack(10);
stack.push(123);
stack.push(456);
stack.push(5264);
int a;
while(stack.pop(a)){
cout<<a<<endl;
}
return 0;
}
jing@jing:~/code/2022-3-29$ ./Stack
5264
456
123
4、编写一个类,实现简单的队列。队列中有以下操作:
> 元素入队 void push(int);
> 元素出队 void pop();
> 读取队头元素 int front();
> 读取队尾元素 int back();
> 判断队列是否为空 bool emty();
> 判断队列是否已满 bool full();
注意循环队列的使用
提示:就是用C++类的方式实现一个队列,然后写出队列的基本操作,入队列、出队列、队列为空、队列为满的函数,以及模拟队列的入队列出队列的操作。
// 4、编写一个类,实现简单的队列。队列中有以下操作:
// > 元素入队 void push(int);
// > 元素出队 void pop();
// > 读取队头元素 int front();
// > 读取队尾元素 int back();
// > 判断队列是否为空 bool emty();
// > 判断队列是否已满 bool full();
#include<bits/stdc++.h>
#define MaxSize 100
using namespace std;
class Queue{
private:
int data[MaxSize];
int front;//队头
int rear;//队尾
public:
Queue(){
front=rear=0;
}
~Queue(){
cout<<"destory"<<endl;
}
bool emty(){
if(front==rear) {
return 1;
}else return 0;
}
bool full(){
if((rear+1)%MaxSize==front){
return 1;
}else return 0;
}
void push(int x);
void pop();
int frontt();
int back();
};
void Queue::push(int x){//进入队列
if(full()){
cout<<"queue is full\n"<<endl;
}else{
rear=(rear+1)%MaxSize;
data[rear]=x;
}
}
void Queue::pop(){
if(emty()){
cout<<"is empty"<<endl;
}else{
front=(front+1)%MaxSize;
}
}
int Queue::frontt(){
if(emty()){
cout<<"queue is empty\n"<<endl;
}else{
return data[(front+1)%MaxSize];
}
}
int Queue::back(){
if(emty()){
cout<<"queue is empty\n"<<endl;
}else{
return data[rear];
}
}
int main(){
Queue queue;
queue.emty();
queue.push(15);
queue.push(20);
queue.push(31);
queue.push(41);
queue.push(6);
queue.push(90);
queue.push(32);
queue.push(10);
cout<<"the back is "<<queue.back()<<endl;
cout<<"the front is "<<queue.frontt()<<endl;
queue.pop();
cout<<"the back is "<<queue.back()<<endl;
cout<<"the front is "<<queue.frontt()<<endl;
return 0;
}
jing@jing:~/code/2022-3-29$ ./queue
the back is 10
the front is 15
the back is 10
the front is 20
destory
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效