欢迎来到study-hard-forever的博客

C++杂文(2)

1、C++函数方式实现并交差程序(注意内容:运算符重载+函数使用)

注意内容:
运算符重载+函数使用。

	//重载小于号<便于排序:sort(v1.begin(), v1.end());
	bool operator <(A &a){
        return id<a.id;
    }

    //输出流方式输出对象更加方便一些(非成员函数,又需要访问对象内部属性,因此采用友元): cout<<v1[i];
    friend ostream & operator<<(ostream &ost,A &obj)  //输出流:ostream而不是ofstream  //istream,ostream
    {
        ost<<obj.getId()<<" "<<obj.getName()<<endl;
        return ost;
    }
	
	//重载等于==号,由于Java不存在运算符重载,因此Java中比较类对象是否相等实现方式不同,下面将会给出Java的比较方式。
    bool operator==(A &obj)
    {
        return id==obj.id;
    }

当然上述重载函数也可以写到类的外部,此时则不需要友元符号标志,不需要标明为友元函数(结果是一样的):

ostream & operator<<(ostream &ost,A &obj)  //输出流:ostream而不是ofstream  //istream,ostream
{
    ost<<obj.getId()<<" "<<obj.getName()<<endl;
    return ost;
}
/*
并交差程序:
(个人想法):设立vector /(数组),里面存放一个元组对象,
并:1.两数组合并,遍历数组,找出一致元素删掉一个(对于某一特定元素,至多有两个相同的元素,分别来自数组一和数组二,因为数组内部本身就没有重复元素)。2.set存储对象?
交:将找出的重复元组放入第三个数组之中。
差:可以找一个较小长度的数组在大的数组里面依次循环,找出相同元素则删去,最后大数组即为所求。

这里采取C++函数方式解决(相对简单明了)。
*/
#include<bits/stdc++.h>
using namespace std;
class A
{
private:
    //数据库元素属性值
    string id;
    string name;
public:
    A(string id,string name)
    {
        this->id=id;
        this->name=name;
    }
    string getId()
    {
        return id;
    }
    string getName()
    {
        return name;
    }

    /*
    int operator <(A &a)
    {
        if(atoi(id.c_str())<atoi(a.id.c_str()))  //c_str()是Borland封装的String类中的一个函数,它返回当前字符串的首字符地址(因此不再是原来的数值,再去比较就错了)
        //if(atoi(id)<atoi(a.id))  //atoi是把字符串转换成整型数的一个函数,原型:int atoi(const char *nptr);  //字符型char应该也没毛病
        {
            return 1;
        }
    }
    */


    //换成这个就对了
    bool operator <(A &a){
        return id<a.id;
    }

    //输出流方式输出对象更加方便一些
    friend ostream & operator<<(ostream &ost,A &obj)  //输出流:ostream而不是ofstream  //istream,ostream
    {
        ost<<obj.getId()<<" "<<obj.getName()<<endl;
        return ost;
    }

    bool operator==(A &obj)
    {
        return id==obj.id;
    }
};
int main()
{
    vector<A>v1;
    vector<A>v2;
    A a1("541","算法");A a2("4684","阿萨");A a3("655","奥维斯");
    A a4("4485","路由");A a5("655","奥维斯");A a6("4485","路由");
    A a7("32985","天润园");
    v1.push_back(a1);v1.push_back(a2);v1.push_back(a3);v1.push_back(a4);
    v2.push_back(a5);v2.push_back(a6);v2.push_back(a7);
    sort(v1.begin(), v1.end());
    sort(v2.begin(), v2.end());

    cout<<"v1: "<<v1.size()<<endl;
    for(int i=0;i<v1.size();i++)
        cout<<v1[i];

    cout<<endl;
    cout<<"v2: "<<v2.size()<<endl;
    for(int i=0;i<v2.size();i++)
        cout<<v2[i];

    vector<A> v_intersection;
    vector<A> v_union;
    vector<A> v_difference;

    set_intersection(v1.begin(), v1.end(),v2.begin(), v2.end(),back_inserter(v_intersection));  //插入迭代器,和下一行作用一致
    //std::set_intersection(v1.begin(),v1.end(),v2.begin(),v2.end(),insert_iterator<vector<A> >(v_intersection,v_intersection.begin()));
    std::set_union(v1.begin(),v1.end(),v2.begin(),v2.end(),insert_iterator<vector<A> >(v_union,v_union.begin()));
    std::set_difference(v1.begin(),v1.end(),v2.begin(),v2.end(),insert_iterator<vector<A> >(v_difference,v_difference.begin()));

    cout<<endl;
    cout<<"作交集得到的集合: "<<v_intersection.size()<<endl;
    for(int i=0;i<v_intersection.size();i++)
        cout<<v_intersection[i].getId()<<" "<<v_intersection[i].getName()<<endl;  //一开始没有加载输出流输出对象

    cout<<endl;
    cout<<"作并集(合并)得到的集合: "<<v_union.size()<<endl;
     for(int i=0;i<v_union.size();i++)
        cout<<v_union[i].getId()<<" "<<v_union[i].getName()<<endl;

    cout<<endl;
    cout<<"作差集得到的集合: "<<v_difference.size()<<endl;
     for(int i=0;i<v_difference.size();i++)
        cout<<v_difference[i].getId()<<" "<<v_difference[i].getName()<<endl;

    cout<<endl;
    cout<<"重载==法获取交集: "<<endl;  //还可获取并集,差集等
    //重载等于号以后的相等元素输出
    for(int i=0;i<v1.size();i++){
        for(int j=0;j<v2.size();j++){
            if(v1[i]==v2[j])
                cout<<"存在相等(交集): "<<v1[i];
                //cout<<"存在相等(交集): "<<v1[i].getId()<<" "<<v1[i].getName()<<endl;
        }
    }
    return 0;
}

/*
参考文章:

c_str(c_str是Borland封装的String类中的一个函数,它返回当前字符串的首字符地址):
https://baike.baidu.com/item/c_str/2622670?fr=aladdin

C 库函数 - atoi():
https://www.runoob.com/cprogramming/c-function-atoi.html

atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数,原型:int atoi(const char *nptr);
https://baike.baidu.com/item/atoi/10931331?fr=aladdin

【C++】关于 std::set_intersection( ) 函数用法:
https://blog.csdn.net/Sim0Hayha/article/details/80043558

C++ set_intersection(STL set_intersection)用法详解:
http://c.biancheng.net/view/556.html

STL之--插入迭代器(back_inserter,inserter,front_inserter的区别):
https://blog.csdn.net/github_35681219/article/details/52564780

*/

result:
在这里插入图片描述

2、Java实现比较类对象是否相同(重写equal、hashcode):

类对象:

package test;

public class Book_Test {

	private String name;
	private String author;

	public Book_Test() {
	}

	public Book_Test(String name, String author) {
		this.name = name;
		this.author = author;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	/*
	 对类对象进行相等比较,要同时重写equals函数和hashcode函数
	(比较单个对象采用equals就可以判断,但是如果是hashset等就无法判断,必须全部重写)
	hashset在添加一个元素的时候,会做如下判断:
	1、如果添加元素的hashcode相等并且 对象equals为true或对象== 时,则认为是同一个元素,不添加到新元素中。
	2、如果不符合上述条件,则认为是一个新元素,添加到set中。
	例:即使p1和p2equals比较时相等,但是hashcode并不一样,所以在往set中添加的时候认为是两个不同的元素,所以才会出现了p1和p2同时在set中的情况。
	*/
	
	@Override
	public boolean equals(Object b) {
		if (this.getName().equals(((Book_Test) b).getName()))
			return true;
		else
			return false;
	}

	//此处若不重写hashCode()则hashSet处理时认为是两个不等对象
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		// result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
}

测试:

package test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Test_Object_Set {

	public static void main(String[] args) {
		Set<Book_Test> test_set = new HashSet<Book_Test>();
		Book_Test book1 = new Book_Test("1234", "1234");
		Book_Test book2 = new Book_Test("123", "456");
		Book_Test book3 = new Book_Test("1234", "1234");
		test_set.add(book1);
		test_set.add(book2);
		test_set.add(book3);

		// 迭代器方式遍历输出set
		Book_Test book_test_iterator;
		Iterator<Book_Test> it = test_set.iterator();
		while (it.hasNext()) {
			book_test_iterator = it.next(); // 不可直接System.out.println(it.next().getName());
			// 那样的话it.next()会指向下面导致输出错误(少值)(甚至可能会set越界导致报错)
			// java.util.NoSuchElementException:某个interator出现了越界.
			// 当set内为类对象且输出参数大于1时,应使用类对象赋值并采用该赋值类对象进行输出
			System.out.println(book_test_iterator.getName());
			System.out.println(book_test_iterator.getAuthor());
		}

	     /**重写equals和hashCode之前:
	      * 运行结果如下:很明显set集合内部顺序是打乱的
	      * 而且在类对象未定义相等的情况下仅仅属性值相等是不能判断两个对象是相等的,因此无法去重
	      * (必须对类对象进行相等的重写定义)
	      * 1234
	      * 1234
	      * 1234
	      * 1234
	      * 123
	      * 456
	      */
	     
	     /**重写equals和hashCode之后(少写哪个都不行):
	      * 123
	      * 456
	      * 1234
	      * 1234
	      */
	}

}

3、Java中toArray()和toArray(T[] a)方法对比(集合转数组):

test_set.toArray(T[]); 与 test_list = test_set.toArray();方法对比,集合转数组的方法:toArray()和toArray(T[] a)方法:
注意内容:
一、

	/*
	* java中的强制类型转换只是针对单个对象的,
	* 想要偷懒将整个数组转换成另外一种类型的数组是不行的,
	* 这和数组初始化时需要一个个来也是类似的。像这样:
	*/
	Object[] arr = list.toArray();
	for (int i = 0; i < arr.length; i++) {
    	String s = (String) arr[i];
    	System.out.println(s);
	}

Set接口中方法说明:
在这里插入图片描述
二、

	//test_set.toArray(T[]);  //数组类型定义什么都可以,没有限制
	test_set.toArray(test_list);  //test_set.toArray(test_list);  不会改变数组原来的数目
	//故在使用前往往先定义好长度:
	//String[] test_list = new String[test_set.size()];
	for(int i=0;i<test_list.length;i++) {
		//System.out.println(test_list[i]);  //若此时打印则打印1、2、3、4这4个元素同时其余空间全部输出为null
	}

三、

	test_list = test_set.toArray();  //test_list = test_set.toArray();  改变了数组原来的数目,使test_list=test_set.toArray();
	for(int i=0;i<test_list.length;i++) {
		//System.out.println(test_list[i]);  //若此时打印则打印1、2、3、4这4个元素同时不再存在多余空间
	}

测试:

package test;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class TestSet {

	public static void main(String[] args) {
		Set<String> test_set = new HashSet<String>();
		String s1 = new String("1");
		String s2 = new String("2");
		String s3 = "3";
		String s4 = "4";
		
		String test_s1 = new String("1");
		String test_s2 = new String("2");
		String test_s3 = "3";
		String test_s4 = "4";
		
		test_set.add(s1);
		test_set.add(s2);
		test_set.add(s3);
		test_set.add(s4);
		
		test_set.add(test_s1);
		test_set.add(test_s2);
		test_set.add(test_s3);
		test_set.add(test_s4);
		
		/**
		 * test_set.toArray(T[]); 与 test_list = test_set.toArray();函数对比
		 * 集合转数组的方法:toArray()和toArray(T[] a)方法
		 */
		
		Object[] test_list = new Object[100];
		
		//test_set.toArray(T[]);  //数组类型定义什么都可以,没有限制
		test_set.toArray(test_list);  //test_set.toArray(test_list);  不会改变数组原来的数目
		//因此在使用时往往先定义好长度:
		//String[] test_list = new String[test_set.size()];
		for(int i=0;i<test_list.length;i++) {
			//System.out.println(test_list[i]);  //若此时打印则打印1、2、3、4这4个元素同时其余空间全部输出为null
		}
		
		
		//test_list = test_set.toArray();  //数组类型只能是Object的,限制返回为Object类型(不支持强转)
		//(强制类型转换只支持单个元素对象而不支持数组或者list等多个对象)
		
		/*
		 * java中的强制类型转换只是针对单个对象的,
		 * 想要偷懒将整个数组转换成另外一种类型的数组是不行的,
		 * 这和数组初始化时需要一个个来也是类似的。像这样:
		 */
		/*Object[] arr = list.toArray();
		for (int i = 0; i < arr.length; i++) {
    		String s = (String) arr[i];
    		System.out.println(s);
		}*/
		
		test_list = test_set.toArray();  //test_list = test_set.toArray();  改变了数组原来的数目,使test_list=test_set.toArray();
		for(int i=0;i<test_list.length;i++) {
			//System.out.println(test_list[i]);   //若此时打印则打印1、2、3、4这4个元素同时不再存在多余空间
		}
		
		//迭代器方式遍历输出set
		 Iterator<String> it = test_set.iterator();
	     while (it.hasNext()) {
	     	System.out.println(it.next());
	    }
	    
	     //可直接将set加载到ArrayList中(这里同时也用迭代器输出):
	    List<String> list = new ArrayList<String>(test_set);
		Iterator<String> it_list = list.iterator();
	     while (it_list.hasNext()) {
	     	System.out.println(it_list.next());
	    }
	}
	
	/** result:上述共输出两次:
	* 1
	* 2
	* 3
	* 4
	* 1
	* 2
	* 3
	* 4
	* /
}
4、虚函数的使用,这里体现了多态性:

有关虚函数和多态的概念可以参考:
虚函数-百度百科
多态-百度百科

例一:

在该例中需要注意const修饰成员函数的功能,下面具体讲解。
(若基类有const修饰而子类没有const修饰则调用时调用基类函数而不是子类函数,认为并非一类函数)。

#include <iostream>
using namespace std;
class Base1   //基类Base1定义
{
public:
    virtual void display() const
    {
        cout << "Base1::display()" << endl;
    }
};
class Base2: public Base1   //公有派生类Base2定义
{
public:
    void display() const
    {
        cout << "Base2::display()" << endl;
    }
};
class Derived: public Base2   //公有派生类Derived定义
{
public:
    void display() const
    {
        cout << "Derived::display()" << endl;
    }
};
void fun(Base1 *ptr)    //参数为指向基类对象的指针
{
    ptr->display();     //"对象指针->成员名"
}
int main()      //主函数
{
    Base1 base1;    //声明Base1类对象
    Base2 base2;    //声明Base2类对象
    Derived derived;    //声明Derived类对象

    fun(&base1);    //用Base1对象的指针调用fun函数
    fun(&base2);    //用Base2对象的指针调用fun函数
    fun(&derived); //用Derived对象的指针调用fun函数

    return 0;
}

result:
在这里插入图片描述
如果不加virtual关键字则不会调用子类对象的函数,结果将是:
在这里插入图片描述

例二:
#include<iostream>
using namespace std;
class A
{
    public:
        virtual void print()
        {
            cout<<"This is A"<<endl;
        }
};
 
class B : public A
{
    public:
        virtual void print()  //建议也把virtual写上
        //void print()
        {
            cout<<"This is B"<<endl;
        }
};
 
 /*
int main()
{
    //main1
    A a;
    B b;
    //这两个class因个体的差异而采用了不同的策略
    //这并不是多态性行为,多态性行为使用的是不同类型的指针,这里没有用到虚函数的功能。
    a.print();
    b.print();
    //输出:
    // This is A
    //This is B
    return 0;
}
*/
int main()
{
    //main2
    A a;
    B b;
    //在A中print()不是虚函数定义时,则返回A的指针引用,输出:
    //This is A
    //This is A

    //在A中print()是虚函数定义时(virtual void print()),则返回各自的指针引用,输出:
    //This is A
    //This is B
    A *p1 = &a;
    A *p2 = &b;
    p1->print();
    p2->print();
    return 0;
}

result:
在这里插入图片描述

例三:java多态:
// https://baike.baidu.com/item/%E5%A4%9A%E6%80%81
public interface Parent//父类接口
{
    public void simpleCall();
}
public class Child_A implements Parent
{
    public void simpleCall();
    {
    //具体的实现细节;
    }
}
 
public class Child_B implements Parent
{
    public void simpleCall();
    {
    //具体的实现细节;
    }
}

Parent pa = new Child_A();
pa.simpleCall()则显然是调用Child_A的方法;
Parent pa = new Child_B();
pa.simpleCall()则是在调用Child_B的方法。

5、关于const修饰:

const 修饰函数参数,返回值,函数体等
c/c++中函数后面加const

6、C++时间类型获取年月日等范例:
/*可以使用std::tm 结构体来进行输出年月日等信息,这是结构体说明:
struct tm {
   int tm_sec;   // seconds of minutes from 0 to 61
   int tm_min;   // minutes of hour from 0 to 59
   int tm_hour;  // hours of day from 0 to 24
   int tm_mday;  // day of month from 1 to 31
   int tm_mon;   // month of year from 0 to 11
   int tm_year;  // year since 1900
   int tm_wday;  // days since sunday
   int tm_yday;  // days since January 1st
   int tm_isdst; // hours of daylight savings time
}

下面是一个范例(输出今天的年月日):

*/
#include<bits/stdc++.h>
#include<ctime>  //注意要使用tm结构体,需要包含此头文件
#include <sys/time.h>
#include<time.h>
using namespace std;
int main() {
    time_t t = time(0);   // get time now
    struct tm * now = localtime( & t );
    cout << (now->tm_year + 1900) << '-'
         << (now->tm_mon + 1) << '-'
         <<  now->tm_mday
         << endl;
}

参考:
c++ 时间类型详解 time_t

7、map使用举例:
#include<bitsdc++.h>
using namespace std;
int main(){
multimap<int,int>m;
multimap<int,int>::iterator mm;
int a,b;
for(int i=1;i<=5;i++)
{
    cin>>a>>b;
    m.insert(make_pair(a,b));
}
for(mm=m.begin();mm!=m.end();mm++)
{
    cout<<mm->first<<" "<<mm->second<<endl;
}
return 0;
}

在这里插入图片描述

8、类模板的使用:
(以求两数中较小的那个数为例):
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
template<class T>
T Min(T x1,T x2)
{
    return (x1<=x2)?x1:x2;
}
int main()
{
    double x1,x2;
    cin>>x1>>x2;
    cout<<Min(x1,x2);
}
应用举例:在JavaEE中我们在Dao层设计时可采用模板格式以便代码多次复用:
package com.edu.dao;

import java.util.List;

public interface IBaseDao<T>{
	public int insert(T o);   //将对象o,添加到数据库内	
	public int insertList(List<T> list);   //将对象集合,添加到数据库内	
	
	public int update(T o);  //利用对象o,修改当前记录	
	
	public int deleteList(int... ids); //利用id的集合,删除该集合中对应id的记录。	
	public int delete(T o);// 从数据库中删除一个记录o	
	public int delete(int id);//利用关键字id 从数据库中删除一个记录
	
		
	public T findById(int id);  //利用id,查找一条记录
	public T find(T o);    //查找对象o
	public List<T> findAll();       //查找所有对象	
	public List<T> findPage(int pageno,int pagesize);  //分页查找所有对象		
	public List<T> findByCondition(String condition); //查找满足条件的所有对象	
	/**
	 * 按条件分页查询记录信息,返回List对象值
	 * @param pageno:页面号
	 * @param pagesize:一个页面中显示的记录条数
	 * @param condition:查询条件
	 * @param order:降序或者升序排序(按id号)
	 * @return:返回查询记录集合
	 */	
	public List<T> findPageCondition(int pageno,int pagesize,String condition,String order);//按条件分页查询	
	public long getRecordCount(String condition);//根据查询条件获取记录 的总条数		

}
posted @ 2021-02-01 17:43  study-hard-forever  阅读(89)  评论(0编辑  收藏  举报