一、选择
1.下列程序段的运行结果是,strlen 函数不包括\0
char c[]="\t\v\\0will\n";
cout<<strlen(c);
1.\t 2.\v 3.\\ 4.0 5.w 6.i 7.l 8.l 9.\n
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char c[]="\t\v\\0will\n";
cout<<strlen(c)<<endl;//9
for(int i=0;i<strlen(c);i++)
{
cout<<c[i]<<endl;
}
printf("%d \n", strlen("IBM\n012\1\\"));//9
printf("%d \n",strlen("\t\"\065\xff\n"));//5
printf("%d \n",strlen("stop\0\n\""));//4
}
char str[]="\tab\n\012\\\""
字符1: \t 转义字符:水平制表符 ,其ASCII 值9(十进制)
程序在输出时将光标移动到下一个制表符位置,这通常是下一个8的倍数的位置(但这也取决于具体的文本编辑器或终端设置)。在文本输出中,"\t" 的作用类似于在键盘上按下 Tab 键,
字符2、3:ab
字符4:\n 转义字符,换行符,其ASCII 值10(十进制) (\r表示回车)
字符5:\012 转义字符,其中012是8进制数,其ASCII值 同\n.
字符6:\\ 转义字符 反斜杠\,其ASCII值 92(十进制)
字符7:\" 转义字符 双引号",其ASCII值 34(十进制)
2. printf("%d \n", strlen("IBM\n012\1\\"));
字符1、2、3: IBM
字符4:\n 转义字符
字符5、6、7:012
字符8:\1 其ASCII值 1(8进制).
字符9:\\ 转义字符 反斜杠\,其ASCII值 92(十进制)
3. printf("%d \n",strlen("\t\"\065\xff\n"));
字符1: \t 转义字符:水平制表符 ,其ASCII 值9(十进制)
字符2:\" 转义字符 双引号",其ASCII值 34(十进制)
字符3:\065 ,代表字符5,其中065为8进制 格式,其ASCII为53(十进制)
字符4:\xff (这个我不知道怎么解释,请其它老师帮助解释)
字符5:\n
4. printf("%d \n",strlen("stop\0\n\""));
字符1、2、3、4:stop
因为strlen()函数遇到\0 就结束了,后面的字符就不去判断了。
C语言中的字符串 是用\0作为 结束符。
2.编译多态基于template(模板)与函数重载,运行多态基于类继承关系和虚函数
3.类型相同的两个指针不能进行的运算是( A )。
A. +
B. -
C.=
D. ==
A. + - 对于两个指针,不能直接进行加法运算(+
)。指针的加法运算没有定义,因为指针指向的是内存中的地址,而地址之间的“加法”没有明确的数学意义。
B. - - 两个类型相同的指针之间可以进行减法运算(-
),其结果表示两个指针所指向地址之间的偏移量(以所指向类型的元素为单位)。
C. = - 两个指针之间可以使用赋值运算符(=
),将一个指针的值赋给另一个指针。
D. == - 两个指针之间可以使用相等运算符(==
)或不等运算符(!=
)来比较它们是否指向相同的内存地址。
二、填空:
1.函数参数传递方式有三种,分别为:值传递、地址传递和(引用传递)。
2.面向对象的程序设计的三大特征是: (封装)、 继承性和多态性。
3.假定A为一个类,则语句A(A&x);是此类(拷贝(复制))构造函数的原型说明。
4.在类的继承与派生中,缺省的继承方式是(私有继承)。
5. C++的两种多态性分别是(编译时)多态性和(运行时)多态性。
6.运算符重载有两种实现方法,一种是通过友元函数来实现,另一种通过(成员)函数来实现。
7.根据数据的组织形式不同,可将文件分为二进制文件和(文本 )文件。
8.若希望类中的成员只能被该类的成员函数及该类的派生类的成员函数访问,则应加上访问权限: ( protected)。
9.假定类A中有一个公用属性的静态数据成员b,在类外不通过对象名访问该成员b的写法为( A::b)。
public,protected,private
1.类实例(即类对象)不能直接访问类的 private成员和protected成员,但是能直接访问类的public成员。
- public:可以从任何地方访问该成员,无论是同一个包内还是不同的包。
- private:只能在该成员所在的类内部访问,类外无法访问。
- protected:可以在同一个包内的任何类和该成员所在类的子类中访问,即使子类在不同的包中。
2.另外无论哪种继承方式,子类都不能直接访问父类的 private成员;但是能直接访问父类的 protected成员和public成员(注意:是子类,而不是类实例),并且能通过父类的protected成员函数和public成员函数间接访问父类的private成员;这句话强调了类与类之间通过继承方式的访问规则,而非类与实例之间的访问规则。
3.子类通过public方式继承父类,则父类中的public、protected和private属性的成员在 子类 中 依次 是 public、protected和private属性,即通过public继承并不会改变父类原来的数据属性。
4.子类通过protected方式继承父类,则父类中的public、protected和private属性的成员在 子类 中 依次 是 protected、protected和private属性,即通过protected继承原来父类中public属性降级为子类中的protected属性,其余父类属性在子类中不变。
5.子类通过private方式继承父类,则父类中的public、protected和private属性的成员在 子类 中 依次 是 private、private和private属性,即通过private继承原来父类中public属性降级为子类中的private属性,protected属性降级为子类中的private属性,其余父类属性在子类中不变。
参考:https://blog.csdn.net/xrinosvip/article/details/119191555
三、程序输出
1.
#include <iostream>
using namespace std;
//先父类后子类 先成员后函数
//先A后B后C A-A B-B C-先成员a-A 后函数C
class A
{
public:
int n;
A(){cout<<"A";
}
};
class B:public A{
public:
B(){cout<<"B";
}
};
class C:public B
{
public:
C():a(),B(){cout<<"C";
}A a;
};
int main()
{
C c;
}
//ABAC
2.基类指针指向派生类对象 调用同名函数(基类虚构)实现的是派生类重写的函数(如果存在)
#include <iostream>
using namespace std;
class Base {
protected:
int *p;
public:
Base(int a=0){p=new int(a);}
~Base(){delete p;}
virtual void print(){cout<<"p->"<<*p<<endl;}
};
class Derived:public Base
{
static int y;
public:
Derived(int b=0){*p=b;y++;}
void print(){cout<<*p<<','<<y<<endl;}
};
int Derived::y=100;
int main()
{
Derived d(50);
Base* pb=&d;
pb->print();//50,101
Derived d1(20);
d1.print();//20,102
}
3.重载运算符区分前缀++后缀++
#include <iostream>
using namespace std;
class B{
int a,b;
public:
B(int aa=0,int bb=0){ a=aa;b=bb;}
void operator ++(); //++a
void operator ++(int); //a++,只能是int
void show(){cout<<a<<'\t'<<b;}
};
void B:: operator ++()
{
a+=2;
b+=5;
}
void B:: operator ++(int)
{
a+=5;
b+=2;
}
int main(){
B x(3,5);
x++;
x.show();
}
//8 7
4.
#include <iostream>
using namespace std;
class A{
public:
A(int n){ num=n;}
int compare(A a)
{
if(this->num==a.num)return 1;
else return 0;
}
private:
int num;
};
int main()
{
A aa(5);
A bb(10);
A cc(5);
cout<<aa.compare(bb)<<'\t';//0
cout << cc.compare(aa)<<endl;//1
}
四、完善程序
1.下列程序通过重载运算符“*”,直接实现两个一维数组对应元素相乘运算。设数组a,b分别为:
int a[10]={1,2,3,4,5,6,7,8,910};
int b[10]={ 1,2,3,4,5,6,7,8,9,10};
相乘后的结果为{1,4,9,16,25,36,49,64,81,100}。同时通过重载运算符“=”,直接实现两个一维数组的赋值运算。试完善程序。
//下列程序通过重载运算符“*”,直接实现两个一维数组对应元素相乘运算。设数组a,b分别为:
//int a[10]={1,2,3,4,5,6,7,8,910};
//int b[10]={ 1,2,3,4,5,6,7,8,9,10};
//相乘后的结果为{1,4,9,16,25,36,49,64,81,100}。同时通过重载运算符“=”,直接实现两个一维数组的赋值运算。试完善程序。
#include <iostream>
#include <string >
using namespace std;
class A {
int x[10];
public:
A(){for(int i=0;i<10;i++) x[i]=0;}
A(int *p)
{
for(int i=0;i<10;i++) x[i]=p[i];
}
A operator *(A a){
A t;
for(int i=0;i<10;i++) t.x[i]=a.x[i]*this->x[i];
//t.x[i]=a.x[i]*t.x[i];错 这里t是新建初始化都为0
//您错误地使用了 t.x[i] 而不是 this->x[i],这样会导致与未初始化的 t 对象的元素相乘
return t;
}
A operator =(A a){
for(int i=0;i<10;i++) x[i]=a.x[i];
return *this;
}
//使用引用传递,并检查自赋值。
// A& operator =(const A& a) {
// if (this != &a) {
// for(int i = 0; i < 10; i++) x[i] = a.x[i];
// }
// return *this;
// }
void show(){
for(int i=0;i<10;i++)
cout<<x[i]<<'\t';}
};
int main()
{
int a[10]={1,2,3,4,5,6,7,8,9,10};
int b[10]={1,2,3,4,5,6,7,8,9,10};
A a1(a),a2(b),a3;
a3=a1*a2;
a3.show();
}
2.下列函数的功能是将-一个新生成的链表按照从小到大的顺序插入到现有的链表中,请完成函数。
//4.下列函数的功能是将-一个新生成的链表按照从小到大的顺序插入到现有的链表中,请完成函数。
struct node {
int data;
node * next;
};
node * Insert(node *head, node *p)//将p指向的结点插入到head代表的链表中
{
node *p1,*p2;
if(head==0){//空链表插入到链表首部
head=p;
p->next=NULL;
return head;
}
if(head->data>=p->data){/非空链表,p的数据项比首节点的数据项小,插入到链首
p->next=head;
head=p;
return head;
}
p2=p1=head;
while(p2!=NULL&&p->data>p2->data){//找到 要插入的位置
p1=p2;p2=p2->next;
}
if(p2->data<p->data){/p代表的结点的数据项最大,插入到表尾
p2->next=p;p->next=0;
}
else
{
p->next=p2;
p1->next=p;
}//插入到p1和p2指向的结点之间
}
3.下面的程序中定义了圆类Circle、长方形类Rect、圆角长方形类RoundRect,其中RoudRect共有继承于Circle 和Rect类。试完成程序。
//下面的程序中定义了圆类Circle、长方形类Rect、圆角长方形类RoundRect,其中RoudRect共有继承于Circle 和Rect类。试完成程序。
#include <iostream>
#include <cstring>
using namespace std;
class Circle{
double radius;
public:
Circle(double r):radius(r) {}
double area(){ return 3.14*radius* radius;}
};
class Rect{
double width, height;
public:
Rect(double w, double h){width=w,height=h;}
double area(){ return height*width;}
};
class RoundRect:public Circle,public Rect{
char color[5];
public:
RoundRect(double r,double w, double h,char *c):Circle(r),Rect(w,h)
{
strcpy(color,c);
}
char *getcolor( ){ return color;}
};
int main()
{
RoundRect r(0.8,1,0.25,"白色");
cout<<r.getcolor()<<endl;
}
深拷贝浅拷贝
- 浅拷贝:(只拷贝指针)浅拷贝是指拷贝对象时仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。换句话说,如果原对象包含对其他对象的引用,那么浅拷贝得到的新对象将仍然包含对原对象中这些引用的指向,而不是指向这些引用的新拷贝。这意味着如果通过新对象修改了这些引用的内容,原对象中的相应内容也会被修改,因为它们实际上指向的是同一个对象。
- 深拷贝:(生成副本对象)深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。也就是说,如果原对象包含对其他对象的引用,深拷贝会创建这些引用的新拷贝,并将新对象的引用指向这些新拷贝,而不是原对象中的引用。这样,新对象和原对象就完全独立了,对新对象的任何修改都不会影响到原对象。
#include <iostream>
#include <cstring> // 用于memcpy
class MyClass {
private:
int* arr;
size_t size;
public:
// 构造函数
MyClass(size_t size) : size(size) {
arr = new int[size];
std::memset(arr, 0, sizeof(int) * size); // 初始化数组为0
}
// 浅拷贝构造函数
MyClass(const MyClass& other) : size(other.size) {
arr = other.arr; // 浅拷贝,只是复制指针,不复制数组内容
}
// 深拷贝构造函数
MyClass(const MyClass& other, bool deepCopy) : size(other.size) {
if (deepCopy) {
arr = new int[size]; // 分配新内存
std::memcpy(arr, other.arr, sizeof(int) * size); // 复制数组内容
} else {
arr = other.arr; // 仍然是浅拷贝
}
}
// 析构函数
~MyClass() {
delete[] arr; // 释放数组内存
}
// 赋值运算符的浅拷贝重载
MyClass& operator=(const MyClass& other) {
if (this != &other) {
size = other.size;
arr = other.arr; // 浅拷贝,只是复制指针
}
return *this;
}
// 赋值运算符的深拷贝重载(可选实现)
MyClass& deepCopyAssign(const MyClass& other) {
if (this != &other) {
delete[] arr; // 先释放旧内存
size = other.size;
arr = new int[size]; // 分配新内存
std::memcpy(arr, other.arr, sizeof(int) * size); // 复制数组内容
}
return *this;
}
// 打印数组内容
void print() const {
for (size_t i = 0; i < size; ++i) {
std::cout << arr[i] << ' ';
}
std::cout << std::endl;
}
};
int main() {
// 创建第一个对象
MyClass obj1(5);
obj1.arr[0] = 1; // 修改数组内容
// 浅拷贝示例
MyClass obj2(obj1); // 使用浅拷贝构造函数
obj2.print(); // 输出:1 0 0 0 0
obj2.arr[1] = 2; // 修改obj2的数组内容
obj1.print(); // 输出:1 2 0 0 0,因为obj1和obj2的arr指向同一块内存
// 深拷贝示例
MyClass obj3(obj1, true); // 使用深拷贝构造函数
obj3.print(); // 输出:1 2 0 0 0,此时obj3的内容是obj1的一个完整拷贝
obj3.arr[2] = 3; // 修改obj3的数组内容
obj1.print(); // 输出:1 2 0 0 0,obj1的内容没有改变,因为obj3有自己的内存拷贝
// 浅拷贝赋值运算符示例
MyClass obj4(5);
obj4 = obj3; // 使用浅拷贝赋值运算符
obj4.print(); // 输出:1 2 3 0 0
obj4.arr[3] = 4; // 修改obj4的数组内容
obj3.print(); // 输出:1 2 3 4 0,因为obj3和obj4的arr现在指向同一块内存
// 注意:这里没有演示深拷贝赋值运算符的使用,因为它需要显式调用deepCopyAssign方法。
// 在实际使用中,通常会重载赋值运算符以提供深拷贝功能,而不是提供另一个方法。
return 0;
}