从C到C++及类与对象

news2024/11/20 6:20:04

目录

从C到C++

嵌入式领域常用的GUI

语法的升级

引用 

默认参数

函数重载

堆内存

概念和思维的升级

类和对象

类的申明

类的成员函数

常成员、常对象(C++推荐const而不用#define, mutable )

静态成员(属于类不属于对象) 

友元(破坏封装) 


        由于电脑没有有线网口和网卡,所以最近一周改为学习C++。而C++的学习只是为了后面做QT开发,人工智能领域多用python和C++做算法,后面我很想往这个方向发展,所以大概会学习这个方向的内容,现在就先学习简单的C++和QT吧,等我的拓展坞到了开始继续学习系统移植和驱动开发。

-------------------------------------------------------------------------------------------------------------------------------

从C到C++

嵌入式领域常用的GUI

 mini一般会用在军工领域,因为是国产的嘛,不容易被入侵

.NET   Windows上用的多我们天天见,微软主推的。

https://baike.baidu.com/item/.NET/156737?fr=aladdin

汽车仪表盘,医院的监护仪,智能家居的显示,还可以开发PC上的软件

语法的升级

引用 

  #include <stdio.h>
   
  int main()
  {
      int a = 100;
      int &b = a;
  
      printf("a = %d\n", a);
      printf("b = %d\n", b);
 
      printf("addr: a = %p\n", &a);
      printf("addr: b = %p\n", &b);
      return 0;
  }

 

我们发现这两个变量的地址和值是相等的,C++支持为变量取别名

这样做有什么好处吗?

交换两个变量的值:

#include <stdio.h>

void swap(int a, int b)
{
    a ^= b;
    b ^= a;
    a ^= b;
}

int main()
{
    int a = 100;
    int b = 10;
    printf("a = %d, b = %d\n", a, b);
    swap(a, b);
    printf("a = %d, b = %d\n", a, b);
    
}

 我们发现不行,那么我们正常应该是这样做的:

#include <stdio.h>

void swap(int *p, int *q)
{
    *p ^= *q;
    *q ^= *p;
    *p ^= *q;
}

int main()
{
    int a = 100;
    int b = 10;
    printf("a = %d, b = %d\n", a, b);
    swap(&a, &b);
    printf("a = %d, b = %d\n", a, b);
    
}

 

没有问题。但是这*来*去的很难让人理解。那么用C++的这个特性就会很好解决这个问题:

#include <stdio.h>
/*
void swap(int *p, int *q)
{
    *p ^= *q;
    *q ^= *p;
    *p ^= *q;
}
*/
void swap(int &a, int &b)
{
    a ^= b;
    b ^= a;
    a ^= b;
}
int main()
{
    int a = 100;
    int b = 10;
    printf("a = %d, b = %d\n", a, b);
    //swap(&a, &b);
    swap(a, b);
    printf("a = %d, b = %d\n", a, b);
    
}

 我们通过取别名的方式解决这个问题就看起来不是那么难懂了。

大家可能好奇这个swap怎么实现的看这个:

a1=a^b

b=b^a1=b^a^b=a

//此时a1=a^b  b=a

a=a1^a=a^b^a=b

默认参数

#include <stdio.h>

void debug(const char *ptr = "----------" )
{
    printf("%s\n", ptr);
}

int main()
{
    debug();
    debug();
    debug();
    debug();
    debug("hello");
    debug("world");
}

 不传参数时使用默认值

这样如果参数很多的时候用户有时可以不用传参直接使用默认值,如果有三个参数但是只传入了两个,它是默认从右到左赋值的。

函数重载

C语言分别比较整型和字符串,两个函数要不同名接下来我们看看C++

 

 这就是函数重载,两个有相同功能的函数处理不同的数据类型可以名字一样,系统会根据你传入的参数自动匹配函数。

#include <stdio.h>
#include <string.h>
/*
int intcmp(int a, int b)
{
    return a-b;
}

int scmp(const char *str1, const char *str2)
{
    return strcmp(str1, str2);
}
*/
int cmp(int a, int b)
{
    return a-b;
}

int cmp(const char *str1, const char *str2)
{
    return strcmp(str1, str2);
}

int main()
{
    printf("%d\n", cmp(1, 2));
    printf("%d\n", cmp("aaaaaa", "bbbb"));
}

堆内存

 

#include <stdio.h>
#include <malloc.h>
#include <string.h>

int main()
{
    char *p = (char*)malloc(10);
    strcpy(p, "hello");

    printf("p: %s\n", p);

    free(p);
}

上面是C的处理方式,下面我们来看看C++的方式

 

 

#include <string.h>

int main()
{
/*
    char *p = (char*)malloc(10);
    strcpy(p, "hello");

    printf("p: %s\n", p);

    free(p);
*/
    int *intp = new int;
    *intp = 100;
    printf("*intp = %d\n", *intp);
    delete intp;

    char *p = new char[10];
    strcpy(p, "hello");
    printf("p: %s\n", p);
    delete [] p;

}

 当我们申请一个的时候就释放一个就行,当我们申请的是一堆也就是数组这种的时候,释放也要释放一堆,再前面加个【】。

概念和思维的升级

 

#include <stdio.h>

int main()
{
	int arr[100] = {0};
	//sizeof ???  strlen ???
	int tail = 0;


	int n = 10;
	while(n--)
		arr[tail++] = n;

	int i = 0;
	for(;i<tail; i++)
		printf("%d, ", arr[i]);
	printf("\n");

	n = 5;
	while(n--)
		arr[tail++] = n;

	for(i=0; i<tail; i++)
		printf("%d, ", arr[i]);
	printf("\n");
}

这样的程序看着很乱,虽然正确执行了,但是相同作用的程序我们可以拿出来写成一个函数,而相关联的变量也可以写进一个集合,封装起来,一般就是结构体

.h文件

#ifndef _ARR_
#define _ARR_

typedef struct arr{
	int data[100];
	int tail;
}ARR;

void init(ARR *arr);
void addtail(ARR *arr, int data);
void show(ARR *arr);

#endif

.c文件

#include "arr.h"
#include <stdio.h>

void init(ARR *arr)
{
	arr->tail = 0;
}

void addtail(ARR *arr, int data)
{
	arr->data[arr->tail++] = data;
}

void show(ARR *arr)
{
	int i = 0;
	for(;i<arr->tail; i++)
		printf("%d, ", arr->data[i]);
	printf("\n");
}

主函数文件

#include "arr.h"

int main()
{
	ARR arr;
	init(&arr);

	int n = 10;
	while(n--)
		addtail(&arr, n);

	show(&arr);


	ARR arr1;
	init(&arr1);

	int i = 0;
	for(;i<10; i++)
		addtail(&arr1, i);

	show(&arr1);
}

 但是这样写再C高级工程师眼中还是不行,我们把他升升级

 .h

#ifndef _ARR_
#define _ARR_

typedef struct arr{
	int data[100];
	int tail;

	void (*addtail)(struct arr *arr, int data);
	void (*show)(struct arr *arr);
}ARR;

void init(struct arr *arr);

#endif

.c

#include "arr.h"
#include <stdio.h>


static void addtail(ARR *arr, int data)
{
	arr->data[arr->tail++] = data;
}

static void show(ARR *arr)
{
	int i = 0;
	for(;i<arr->tail; i++)
		printf("%d, ", arr->data[i]);
	printf("\n");
}

void init(ARR *arr)
{
	arr->tail = 0;

	arr->addtail = addtail;
	arr->show = show;
}

主函数


#include "arr.h"

int main()
{
	ARR arr;
	init(&arr);

	int n = 10;
	while(n--)
		arr.addtail(&arr, n);


	arr.show(&arr);

//	arr.tail = 0;

	arr.show(&arr);

}

这样就有面向对象的意思了。

但是避免不了,C语言一个语句就能操纵成员值的特性。一个不留神就会导致项目的崩溃。

还有已经找到arr了为什么还要再传一次,直接再内部处理不行吗?

而且你都已经定义了对象还要再初始化,能不能再定义对象的时候就初始化呢。

类和对象

类的申明

 

#include <stdio.h>
class A{
    int a;
};

int main()
{
    A x;
    x.a = 100;
}

 他说这个成员是私有的,如果这是一个结构体肯定没问题,这就是C++升级的地方

#include <stdio.h>
class A{
    void show()
    {
        printf("xxxxxxxxxxxxxxxx\n");
    }
    int a;
};

int main()
{
    A x;
    x.a = 100;
}

 C++还可以在这里面写函数。

但是一编译同样他也是私有的。

然后我们修饰一下:

#include <stdio.h>
class A{
public:
    void show()
    {
        printf("xxxxxxxxxxxxxxxx\n");
    }
private:
    int a;
};

int main()
{
    A x;
    x.show();
//    x.a = 100;
}

没有问题了。 这就是公有型和私有型。当你想让别人直接用的时候就让他是公有的,不想让别人直接用就让他是私有的。

那么我想用这个私有的怎么办呢

 

#include <stdio.h>
class A{
public:
    void show()
    {
        printf("xxxxxxxxxxxxxxxx\n");
    }
    void setdata(int data)
    {
        a = data;
    }
    int getdata(void);
private:
    int a;
};
int A::getdata(void)
{
    return a;
}

int main()
{
    A x;
    x.show();
    x.setdata(100);
    printf("%d\n", x.getdata() );
//    x.a = 100;
}

我们设置这个私有的成员可以直接再这个公有成员里写个函数,而调用它可以再里面也可以再外面,因为C++规定只要是类的成员就可以使用它的私有变量。

#include <stdio.h>
class A{
public:
    A()
    {
        printf("construct !!!!!!!!!!!\n");
    }
    void show()
    {
        printf("xxxxxxxxxxxxxxxx\n");
    }
    void setdata(int data)
    {
        a = data;
    }
    int getdata(void);
private:
    int a;
};
int A::getdata(void)
{
    return a;
}

int main()
{
    A x;
    x.show();
    x.setdata(100);
    printf("%d\n", x.getdata() );
//    x.a = 100;
}

我们发现这里多了一个和类同名的函数,这就是类的构造函数,再对象生成的时候一定会先调用这个函数,我们开始的程序虽然没有写,但是他会默认的生成一个无参构造函数。

构造函数一般用来初始化

#include <stdio.h>
class A{
public:
    A()
    {
        printf("construct !!!!!!!!!!!\n");
        a = 100;
    }

    A(int data)
    {
        a = data;
    }
    void show()
    {
        printf("xxxxxxxxxxxxxxxx\n");
    }
    void setdata(int data)
    {
        a = data;
    }
    int getdata(void);
private:
    int a;
};
int A::getdata(void)
{
    return a;
}

int main()
{
    A x(100);
    x.show();
//  x.setdata(100);
    printf("%d\n", x.getdata() );
//    x.a = 100;
}

C++支持函数重载所以我们写一个同名的有参构造函数,再生成对象的时候传进去一个100,他会将这个100传给a。 

 既然有构造就一定有销毁,他的名字叫析构函数,和类同名,但是前面要加个取反(~)

#include <stdio.h>
class A{
public:
    A()
    {
        printf("construct !!!!!!!!!!!\n");
        a = 100;
    }

    A(int data)
    {
        a = data;
    }

    ~A()
    {
        printf("ddddddddddddddddddddddddd\n");
    }
    void show()
    {
        printf("xxxxxxxxxxxxxxxx\n");
    }
    void setdata(int data)
    {
        a = data;
    }
    int getdata(void);
private:
    int a;
};
int A::getdata(void)
{
    return a;
}

int main()
{
    A x(100);
    x.show();
//  x.setdata(100);
    printf("%d\n", x.getdata() );
//    x.a = 100;
}

 我们发现我们没调用他但是再最后他自动执行了。对象再栈区创建,再他的生存域结束后会调用这个函数。学了这么多我们用C++来回头完成那个实现一个数组再尾部加

arr.h

#ifndef _ARR_
#define _ARR_

#if 0
typedef struct arr{
	int data[100];
	int tail;

	void (*addtail)(struct arr *arr, int data);
	void (*show)(struct arr *arr);
}ARR;

void init(struct arr *arr);
#endif

class ARR{
public:
	ARR():tail(0){
//		tail = 0;
	}

	void addtail(int data);
	void show(void);
	
	friend void rev(ARR &arr);
	
private:
	int data[100];
	int tail;
};


#endif

arr.c

#include "arr.h"
#include <stdio.h>


void ARR::addtail(int data)
{
	this->data[tail++] = data;
}

void ARR::show(void)
{
	int i = 0;
	for(;i<tail; i++)
		printf("%d, ", data[i]);
	printf("\n");
}

/*
void init(ARR *arr)
{
	arr->tail = 0;

	arr->addtail = addtail;
	arr->show = show;
}
*/

main.c

#include "arr.h"

void rev(ARR &arr)
{
	int i = 0;
	for(;i<arr.tail/2; i++)
	{
		int tem = arr.data[i];
		arr.data[i] = arr.data[arr.tail-i-1];
		arr.data[arr.tail-i-1] = tem;
	}
}

int main()
{
#if 0
	ARR arr;
	init(&arr);

	int n = 10;
	while(n--)
		arr.addtail(&arr, n);


	arr.show(&arr);

//	arr.tail = 0;

	arr.show(&arr);
#endif
	ARR arr;

	arr.addtail(1);
	arr.addtail(2);
	arr.addtail(3);
	arr.addtail(4);

	arr.show();
	//reverse
	rev(arr);

	arr.show();
}

用什么语言都可以实现面向对象,只不过用面向对象的语言更加适合。写的程序不是那么赘余。C语言的高手一样可以用C写出面向对象的感觉就像前面写的那样,用函数指针,回调机制什么的,比如写Linux内核的那些大佬。为了给我们提供接口,同时防止我们破坏,他们就是用面向对象的思维写的内核。但是内核大部分都是C实现的,只有少量的汇编。

类的成员函数

 我们详细的来学习一下,避免以后开发时出现错误

#include <stdio.h>

calss A{
public:
    ~A(){
        printf("A~~~~~~~~~~~~~~~~~\n");
    }
};
int main()
{
    A x;
    A m(100);
    A y = 10;
    A z = y;
}

 

class拼错了哈哈

 

他想要一个整型我们就加个整型

加了还是不行,因为构造函数如果有有参的了就不会自动生成无参的了

 补上这个无参构造函数

#include <stdio.h>

class A{
public:
    A(int data){
        printf("A(int)\n");
    }
    A(){
        printf("A()\n");
    }
    ~A(){
        printf("A~~~~~~~~~~~~~~~~~\n");
    }
};
int main()
{
    A x;
    A m(100);
    A y = 10;
    A z = y;
}

 有参构造调用两次,无参构造调用一次。析构调用四次

原因呢就是第二个是显式调用,第三个是隐式调用,第四个也是隐式调用,但是在他调用的是拷贝函数。还有下面再堆中申请的也会隐式调用

#include <stdio.h>

class A{
public:
    A(int data){
        printf("A(int)\n");
    }
    A(){
        printf("A()\n");
    }
    ~A(){
        printf("A~~~~~~~~~~~~~~~~~\n");
    }
};
int main()
{
    A *p = new A(1000);
    A x;
    A m(100);
    A y = 10;
    A z = y;
    delete(p);
}

 但是这种拷贝有时是好事又是又是一种坏事:

#include <stdio.h>
class A{
public: 
    A()
    {
        printf("A()\n");
        p = new char[10];
    }

    ~A()
    {
        printf("~A()\n");
        delete [] p;
    }
private:
    char *p;
};
int main()
{
    A x;
}

 

 现在没有问题正常运行,然后我们稍微修改一下

#include <stdio.h>
class A{
public: 
    A()
    {
        printf("A()\n");
        p = new char[10];
    }

    ~A()
    {
        printf("~A()\n");
        delete [] p;
    }
private:
    char *p;
};
int main()
{
    A x;
    A y = x;
}

 问题来了段错误:

由于y的值是x所以他没有调用构造函数调用的是拷贝函数,但是这个构造函数涉及到了指针,所以我们需要完善一下这个拷贝函数,我们刚刚的拷贝是浅拷贝相当于只是拷贝过来了一个快捷方式,而没有将内容拷贝过来。把内容也拷贝过来的叫深拷贝,这就需要一个新的概念叫拷贝构造函数。

#include <stdio.h>
#include <string.h>

class A{
public: 
    A()
    {
        printf("A()\n");
        p = new char[10];
        strcpy(p, "hello");
    }

    A(const A &x)
    {
        printf("A(const A &x)\n");
        p = new char[10];
        strcpy(p, x.p);
    }

    ~A()
    {
        printf("~A()\n");
        delete [] p;
    }
private:
    char *p;
};
int main()
{
    A x;
    A y = x;
}

 这次没有段错误了,并且第二个构造函数是拷贝构造函数的内容。

浅拷贝使用的是同一个资源两个人都释放这一个资源导致段错误。

那么当再主函数中直接     x = y 时我们怎么解决呢后面再说。

说一下this关键字

#include <stdio.h>
#include <string.h>

class A{
public: 
    A()
    {
        printf("A()\n");
        p = new char[10];
        strcpy(p, "hello");

        printf("p: %s\n", p);
        printf("p: %s\n", this->p);
    }

    A(const A &x)
    {
        printf("A(const A &x)\n");
        p = new char[10];
        strcpy(p, x.p);
    }

    ~A()
    {
        printf("~A()\n");
        delete [] p;
    }
private:
    char *p;
};
int main()
{
    A x;
    A y = x;
}

当局部变量和成员变量重名时,使用this可以区分局部变量和成员变量,this.变量名可以访问成员变量 。这个实例不好区分。但是大概就是干这个用的,还有别的作用可以自己查查比较多。

常成员、常对象(C++推荐const而不用#define mutable

 !!! const 数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的(static 例外)。

 

#include <stdio.h>

class A{
public:
    A(int a = 50, int data = 1000):b(data){//b = data
        this->a = a;
        printf("AAAAAAAAAAAAAAA\n");
    }
    ~A(){
        printf("~~~~~~~~~~~~~~~\n");
    }

    void show(void)const
    {
        printf("b = %d\n", b);
        printf("a = %d\n", a);
    }
private:
    int a;
    const int b;
};

int main()
{
    A x(10);
    x.show();

    A y(100);
    y.show();

    A z;
    z.show();
}

 这样有没有参数都能调用构造函数,这里析构函数中b的写法就是说明他是一个常量。

 

#include <stdio.h>

class A{
public:
    A(int a = 50, int data = 1000):b(data){//b = data
        this->a = a;
        printf("AAAAAAAAAAAAAAA\n");
    }
    ~A(){
        printf("~~~~~~~~~~~~~~~\n");
    }

    void show(void)const
    {
        printf("b = %d\n", b);
        printf("a = %d\n", a);
        a++;
    }
private:
    int a;
    const int b;
};

int main()
{
    A x(10);
    x.show();

    A y(100);
    y.show();

    A z;
    z.show();
}

我们加了个a++报错了,他说const类型的我们不能修改。 他是只读的。

静态成员(属于类不属于对象) 

 

#include <stdio.h>

class A{
public:
    void func(void)
    {
        printf("xxxxxxxxxxx\n");
    }
};

int main()
{
    A a;
    a.func();
}

 

#include <stdio.h>

class A{
public:
    static void func(void)
    {
        printf("xxxxxxxxxxx\n");
    }
};

int main()
{
    A a;
    a.func();

    A::func();
}

 当我们去掉static时

所以我们想没有对象直接调用类的成员函数,就需要用static修饰一下

 

#include <stdio.h>

class A{
public:
    static void func(void)
    {
        printf("xxxxxxxxxxx\n");
    }
    static int data;
};

int A::data = 10;

int main()
{
    A a;
    a.func();
    A::func();

    A x;
    x.data = 100;
    printf("x.data = %d\n", x.data);

    A::data = 1000;

    printf("x.data = %d\n", x.data);
}

 

所以说static是基于类的不是基于对象的。 

友元(破坏封装) 

 希望别人可以随便用自己,破坏面向对象,那么这样有什么好处呢?

比如我需要给数组排序:

//arr.c
#include "arr.h"
#include <stdio.h>


void ARR::addtail(int data)
{
	this->data[tail++] = data;
}

void ARR::show(void)
{
	int i = 0;
	for(;i<tail; i++)
		printf("%d, ", data[i]);
	printf("\n");
}

/*
void init(ARR *arr)
{
	arr->tail = 0;

	arr->addtail = addtail;
	arr->show = show;
}
*/
//arr.h
#ifndef _ARR_
#define _ARR_

#if 0
typedef struct arr{
	int data[100];
	int tail;

	void (*addtail)(struct arr *arr, int data);
	void (*show)(struct arr *arr);
}ARR;

void init(struct arr *arr);
#endif

class ARR{
public:
	ARR():tail(0){
//		tail = 0;
	}

	void addtail(int data);
	void show(void);
	
	friend void rev(ARR &arr);
	
private:
	int data[100];
	int tail;
};


#endif

 

//main.c
#include "arr.h"

void rev(ARR &arr)
{
	int i = 0;
	for(;i<arr.tail/2; i++)
	{
		int tem = arr.data[i];
		arr.data[i] = arr.data[arr.tail-i-1];
		arr.data[arr.tail-i-1] = tem;
	}
}

int main()
{
#if 0
	ARR arr;
	init(&arr);

	int n = 10;
	while(n--)
		arr.addtail(&arr, n);


	arr.show(&arr);

//	arr.tail = 0;

	arr.show(&arr);
#endif
	ARR arr;

	arr.addtail(1);
	arr.addtail(2);
	arr.addtail(3);
	arr.addtail(4);

	arr.show();
	//reverse
	rev(arr);

	arr.show();
}

 

一堆程序可以用一个friend关键字解决 

他是私有的我们不能用,接下来我们加上friend

#include <stdio.h>

class A{
public:
    A()
    {
        x = 100;
    }
    friend class B;

private:
    int x;
};

class B{
public:
    void printfA(A &x);
};
void B::printfA(A &x)
{
    printf("%d\n", x.x);
}

int main()
{
    A a;
//    printf("%d\n", a.x);
    B b;
    b.printfA(a);
}

 如果B中还有其它函数我们最好是只把需要的函数声明称朋友。

#include <stdio.h>

class A{
public:
    A()
    {
        x = 100;
    }
//    friend class B;
    friend void B::printfA(A &x);
private:
    int x;
};

class B{
public:
    void printfA(A &x);
    void show(void)
    {
        
    }
};
void B::printfA(A &x)
{
    printf("%d\n", x.x);
}

int main()
{
    A a;
//    printf("%d\n", a.x);
    B b;
    b.printfA(a);
}

 但是说不认识,我们没有定义,确实没有,我们在最前面class B声明一下

还是不行他说我们声明的不完整,主要是想表达它可以这样,这种破坏封装的行为C++不太允许。

我们调换一下顺序:

#include <stdio.h>
class A;
class B{
public:
    void printfA(A &x);
};

class A{
public:
    A()
    {
        x = 100;
    }
//    friend class B;
    friend void B::printfA(A &x);
private:
    int x;
};

void B::printfA(A &x)
{
    printf("%d\n", x.x);
}

int main()
{
    A a;
//    printf("%d\n", a.x);
    B b;
    b.printfA(a);
}

 下面用C++来实现一个顺序表

#include <cstdlib>
#include <iostream>
using namespace std;
const int MAXSIZE = 100;
using ElemType = int;//可以采用自定义类型,重载类的输入、输出、==、>等
class SqList
{
private:
    ElemType* elem;
    int length;
public:
    //1.初始化
    SqList()
    {
        elem = new ElemType[MAXSIZE];
        if (!elem)
        {
            cout << "初始化错误!" << endl;
            exit(0);
        }
        length = 0;
    }
    ~SqList()
    {
        delete[]elem;
    }
    //2.取值(按照位置i)
    bool GetElem(const int&i, ElemType& e)
    {
        if (i<1 || i>length)
        {
            cout << "位置错误!" << endl;
            return false;
        }
        e = elem[i - 1];
        return true;
    }
    //3.查找(按值查找)
    int LocateElem(const ElemType &e)
    {
        int i;
        for (i=0;i<=length-1;i++)
        {
            if (e == elem[i])
            {
                return i+1;//实际序号i+1
            }
        }
        return false;//查找失败,返回false
    }
    //4.插入(按照位置i)
    bool ListInsert(const int &i, const ElemType &e)
    {
        if (i<1 || i>length + 1)
        {
            cout << "位置错误!" << endl;
            return false;
        }
        if (length == MAXSIZE)
        {
            cout << "当前存储空间已满!" << endl;//可以在大于等于的情况下再次进行动态分配
            return false;
        }
        int j;
        for (j = length - 1; j >= i - 1; j--)
        {
            elem[j+1] = elem[j];//强记忆点
        }
        elem[i - 1] = e;
        ++length;
        return true;
    }
    //5.删除(按照位置i)
    bool ListDelete(const int &i)
    {
        if (i<1 || i>length)
        {
            cout << "位置错误!" << endl;
            return false;
        }
        int j;
        for (j = i; j <= length - 1; j++)
        {
            elem[j-1] = elem[j];
        }
        --length;
        return true;
    }
    //修改元素
    bool AmendElem(const ElemType &oldelem,const ElemType &newelem)
    {
        int i = LocateElem(oldelem);
        if (!i)
        {
            cout << "旧元素错误" << endl;
            return false;
        }
        elem[i - 1] = newelem;
        return true;
    }
    //展示顺序表
    void Display()
    {
        int i = 0;
        for (i = 0; i <= length - 1; i++)
        {
            cout << elem[i] << '\t';
        }
        cout << endl;
    }
    //重载[]运算符
    ElemType& operator[](const int &i)
    {
        if (i<0 || i>length - 1)
        {
            cout << "位置错误!" << endl;
            exit(0);
        }
        return elem[i];
    }
    //顺序表长度
    int GetLength()
    {
        return length;
    }
};
int main()
{
    SqList list;
    int i,num;
    ElemType e;
    cout << "请输入数据个数:" << endl;
    cin >> num;
    for (i = 1; i <= num; i++)
    {
        cout << "input" << endl;
        cin >> e;
        list.ListInsert(i, e);
    }
    cout << "原顺序表:" << endl;
    list.Display();
    cout << "再次添加:" << endl;
    cout << "请输入再次添加个数:" << endl;
    cin >>num;
    for (i = 0; i < num; i++)
    {
        cin >> e;
        if (list.ListInsert(list.GetLength() + 1, e))
        {
            cout << "再次添加成功" << endl;
        }
    }
    list.Display();
    cout << "operator[]" << endl;
    cout <<list[3] << endl;
    cout << "删除元素" << endl;
    cout << "input" << endl;
    cin >> i;
    if (list.ListDelete(i))
    {
        cout << "删除元素成功" << endl;
    }
    list.Display();
    cout << "查找元素的位置:" << endl;
    cout << "input" << endl;
    cin >> e;
    if (!list.LocateElem(e))
    {
        cout<< "查找失败!" <<endl;
    }
    else
    {
        cout << "元素位置为:" << list.LocateElem(e) << endl;
    }
    cout << "修改元素:" << endl;
    ElemType olde, newe;
    cout << "input old:" << endl;
    cin >> olde;
    cout << "input new:" << endl;
    cin >> newe;
    if (list.AmendElem(olde, newe) )
    {
        cout << "修改成功" << endl;
    }
    list.Display();
    return 0;
}

 

---------------------------------------------------------------------------------------------------------------------------------

最近事情有点多,花了近一周确认某人的态度,前几天影响较大耽误了学习。这几天又因为要过年了,被抓去当了壮丁。现在没什么事可以影响我了,接下来会抓紧学习。一篇文章写了四天,太不像话了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/163102.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Opencv实战案例——模板匹配实现银行卡号识别(附详细介绍及完整代码下载地址)

Opencv目录1.项目意义2.模板匹配3.图像二值化3.1全局阈值3.2全局阈值代码即效果展示3.3 自适应阈值3.4自适应阈值代码即效果展示4.轮廓筛选4.1轮廓检测4.2绘制轮廓4.3轮廓筛选代码及效果展示5.形态学变化5.1腐蚀5.2膨胀5.3开运算和闭运算、礼帽和黑帽6.项目实战6.1读取图片转化…

next_permutation函数讲解

目录 前言&#xff1a; 简要概述&#xff1a; 例题&#xff08;1&#xff09;&#xff1a; P1088 [NOIP2004 普及组] 火星人 题目描述 输入格式 输出格式 输入输出样例 说明/提示 代码&#xff08;1&#xff09;&#xff1a; 例题&#xff08;2&#xff09;&#xf…

如何开发 Vite 3 插件构建 Electron 开发环境?(文末附视频讲解)

开发新版本 Vue 项目推荐你使用 Vite 脚手架构建开发环境&#xff0c;然而 Vite 脚手架更倾向于构建纯 Web 页面&#xff0c;而不是桌面应用&#xff0c;因此开发者要做很多额外的配置和开发工作才能把 Electron 引入到 Vue 项目中&#xff0c;这也是很多开发者都基于开源工具来…

用户多兴趣建模MIND

1. 概述 在工业界&#xff0c;一个完整的推荐系统中通常包括两个阶段&#xff0c;分别为召回阶段和排序阶段。在召回阶段&#xff0c;根据用户的兴趣从海量的商品中去检索出用户&#xff08;User&#xff09;可能感兴趣的候选商品&#xff08; Item&#xff09;&#xff0c;满…

JavaEE进阶第二课:Spring创建与使用

上一篇我们介绍了Spring的概念&#xff0c;知道了Spring是众多工具方法的IoC容器。 但是纸上谈兵终觉浅&#xff0c;这一篇文章就来介绍Spring创建与使用&#xff0c; 注之后我们对对象的称呼就叫Bean 1.1Spring项目的创建与配置 1.创建maven项目&#xff0c;语言选java&…

【1819. 序列中不同最大公约数的数目】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个由正整数组成的数组 nums 。 数字序列的 最大公约数 定义为序列中所有整数的共有约数中的最大整数。 例如&#xff0c;序列 [4,6,16] 的最大公约数是 2 。 数组的一个 子序列 本质是一个序…

Python(16):Numpy之array数组的数值计算

目录 0. 相关文章链接 1. 创建Array数组 2. 基本数值计算 2.1. numpy中的函数 2.2. 数组中的函数 3. 指定维度进行计算 3.1. numpy中的函数 3.2. 数组中的函数 4. 复杂计算 4.1. 统计乘机 4.2. 获取对应值的索引位置 4.3. 求平均值 4.4. 求标准差 4.5. 求方差 4…

【MFEN:轻量级多尺度特征提取:SR网络】

MFEN: Lightweight multi-scale feature extraction super-resolution network in embedded system &#xff08;MFEN&#xff1a;嵌入式轻量级多尺度特征提取超分辨率网络&#xff09; 深度卷积神经网络&#xff08;CNN&#xff09;在超分辨率&#xff08;SR&#xff09;方面…

基于java springboot+mybatis爱游旅行平台前台+后台设计实现

基于java springbootmybatis爱游旅行平台前台后台设计实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获…

PCI、PCI-X、PCI-E、PCI-E Card、Mini PCI-E、M.2、Add-in Card 这些概念你搞清楚了吗

搞硬件或通信的“攻城狮”们&#xff0c;免不了要和各种通信协议及接口打交道。比如&#xff0c;我们经常接触PCI、PCI-X、PCI-E、PCI-E Card、Mini PCI-E、M.2(NGFF)、Add-in Card这些概念&#xff0c;作为“攻城狮”队伍中的一员&#xff0c;你搞清楚它们之间的关系了吗&…

Linux第一个小程序-进度条

目录 \r&&\n 行缓冲区概念 倒计时程序 进度条代码 \r&&\n 回车概念换行概念 \n[rootVM-12-17-centos lesson8]# touch test.c [rootVM-12-17-centos lesson8]# touoch Makefile bash: touoch: command not found [rootVM-12-17-centos lesson8]# touch Mak…

Python:每日一题之完全二叉树的权值

题目描述 给定一棵包含 N 个节点的完全二叉树&#xff0c;树上每个节点都有一个权值&#xff0c;按从 上到下、从左到右的顺序依次是 A1​,A2​,⋅⋅⋅AN​&#xff0c;如下图所示&#xff1a; 现在小张要把相同深度的节点的权值加在一起&#xff0c;他想知道哪个深度的节点 权…

【Linux操作系统】Linux进程状态和两个特殊进程

文章目录一.一套普适性的进程状态理论1.运行2.阻塞3.挂起二.一套具体的Linux进程状态1.R-运行2.S-睡眠3.T-暂停5.t-被追踪三.僵尸进程和孤儿进程1.僵尸进程2.孤儿进程一.一套普适性的进程状态理论 1.运行 由于CPU数量相对于进程数量来说少之又少,所以CPU维护了一个运行队列,方…

Synchronized底层原理系列之Synchronized的偏向锁实现原理

作者简介&#xff1a;专注于研究Linux内核、Hotspot虚拟机、汇编语言、JDK源码、各大中间件源码等等喜欢的话&#xff0c;可以三连关注~上篇文章已经对Synchronized关键字做了初步的介绍&#xff0c;从字节码层面介绍了Synchronized关键字&#xff0c;最终字节码层面就是monito…

【Linux】 iptables 入门简介

文章目录前言作用持久化和恢复执行的顺序前言 简单地说&#xff0c;iptables是Linux的防火墙程序。它将使用表监控进出服务器的流量。这些表包含称为链的规则集&#xff0c;这些规则将过滤传入和传出数据包。 作用 当数据包与规则匹配的时候&#xff0c;会为其指定一个目标&a…

基于幂等表思想的幂等实践

一、为什么需要幂等 分布式场景下&#xff0c;多个业务系统间实现强一致的协议是极其困难的。一个最简单和可实现的假设就是保证最终一致性&#xff0c;这要求服务端在处理一个重复的请求时需要给出相同的回应&#xff0c;同时不会对持久化数据产生副作用&#xff08;即多次操…

【Linux】Linux下调试器gdb的使用

&#x1f451;作者主页&#xff1a;安 度 因 &#x1f3e0;学习社区&#xff1a;StackFrame &#x1f4d6;专栏链接&#xff1a;Linux 文章目录一、前言二、铺垫三、指令集和使用1、指令集2、演示四、结语如果无聊的话&#xff0c;就来逛逛 我的博客栈 吧! &#x1f339; 一、前…

通信原理与MATLAB(十三):AMI的编解码

目录1.AMI的的编解码原理1.1 AMI编码原理1.2 AMI解码原理2.AMI编解码的代码3.AMI编解码结果图4.AMI的误码率曲线4.1 原理4.2 AMI的误码率曲线代码4.3 误码率曲线图1.AMI的的编解码原理 1.1 AMI编码原理 如下图所示&#xff0c;AMI的编码原理:将原始码元的1转换成1,0转换成-1。…

快过年了,用Python康康哪一家足浴店可以带朋友去玩.....

人生苦短&#xff0c;我用Python 首先肯定是去正经足浴店&#xff0c; 毕竟一年出差也不少&#xff0c; 大家都很辛苦&#xff0c; 好不容易放假了&#xff0c; 约上好兄弟一起去放松放松~ 所需环境 python 3.8 解释器pycharm 编辑器 所需模块 requests 数据来源分析 …

Silane-PEG-NH2 氨基聚乙二醇硅烷 NH2-PEG-Silane结构式

英文名称&#xff1a;Silane-PEG-NH2 Silane-PEG-Amine 中文名称&#xff1a;硅烷-聚乙二醇-氨基 分子量&#xff1a;1k&#xff0c;2k&#xff0c;3.4k&#xff0c;5k&#xff0c;10k&#xff0c;20k。。。 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 用 途…