c++学习第十三

1)循环引用的案例及解决办法:

cpp 复制代码
#include <iostream>
#include <memory>
using  namespace std;
class A;

class B
{
public:
	B(){cout<<"B constructor---"<<endl;}
	~B(){cout<<"B deconstructor----"<<endl;}
	std::weak_ptr<A> pA; //如果是std::shared_ptr,则会造成引用计数永远无法归0,资源不会被释放;
};

class A
{
public:
	A(){cout<<"A constructor---------"<<endl;}
	~A(){cout<<"A deconstructor----------------"<<endl;}
	std::shared_ptr<B> pB;
};

int main()
{
	std::shared_ptr<A> pAA = make_shared<A>();
	std::shared_ptr<B> pBB = make_shared<B>();
	pAA->pB = pBB;
	pBB->pA = pAA;
	return 0;
}

2)emplace紧调用一次构造函数,push_back调用一次构造,一次拷贝,测试代码如下:

所以:优先使用emplace成员函数。

cpp 复制代码
#include<iostream>
#include<vector>
#include<algorithm>
#include<set>

using namespace std;

struct SBook
{
public:
	SBook() : bookName(""), price(0)
	{
		std::cout << "default construct: " << bookName << std::endl;
	}
 
	SBook(std::string bookName_, int price_) : bookName(bookName_), price(price_)
	{
		std::cout << "construct: " << bookName << std::endl;
	};
 
	 SBook(const SBook& rhs) : bookName(rhs.bookName), price(rhs.price)
	{
		std::cout << "copy construct: " << bookName << std::endl;
	}
 
	~SBook()
	{
		std::cout << "deconstruct: " << bookName << std::endl;
	}
 
	bool operator <(const SBook& rhs) const
	{
		return bookName < rhs.bookName;
	}
 
public:
	std::string bookName;
	int price;
};
 
int main(int argc, char *argv[])
{
 
	// 测试vector
	vector<SBook> books;
	// 预先分配,否则整个vector在容量不够的情况下重新分配内存
	books.reserve(100);
 
	std::cout << "test push_back:" << endl;
	books.push_back(SBook("C++从入门到放弃", 1));
	std::cout << endl;
 
	std::cout << "test emplace_back:" << endl;
	books.emplace_back("水浒传", 2);
	std::cout << endl;
 
	std::cout << "test emplace_back default:" << endl;
	books.emplace_back();
	auto& book = books.back();
	book.bookName = "红楼梦";
	book.price = 5;
	std::cout << endl;
 
	std::cout << "test emplace:" << endl;
	auto it = books.emplace(books.end());
	it->bookName = "西游记";
	it->price = 3;
	std::cout << endl;
 
	std::cout << "output all books: " << endl;
	for_each(books.begin(), books.end(), [](const SBook& book)->void
	{
		std::cout << book.bookName << endl;
	});
	std::cout << endl;
 
 
	// 测试set
	set<SBook> bookSet;
 
	std::cout << "test bookSet insert:" << endl;
	bookSet.insert(SBook("十万个为什么", 1));
	std::cout << endl;
 
	std::cout << "test bookSet emplace:" << endl;
	bookSet.emplace("新华字典", 2);
	std::cout << endl;
 
	std::cout << "output bookset: " << endl;
	for_each(bookSet.begin(), bookSet.end(), [](const SBook&book)->void
	{
		std::cout << book.bookName << endl;
	});
	std::cout << endl;
        return 0 ;
}

3)unordered_map的使用

cpp 复制代码
#include <iostream>
#include <unordered_map>
using  namespace std;

template<class K,class V>
using umap = std::unordered_map<K,V>;

int main(void)
{
	umap<string,string> m{{"111","bbb"},{"222","ddd"}};
	cout<<m["111"]<<endl;  //显示key为"111"的value;
	return 0;
}

4)利用模板类的参数,自动生成友元函数;

芙蓉楼送辛渐

王昌龄

寒雨连江夜入吴,

平明送客楚山孤。

洛阳亲友如相问,

一片冰心在玉壶;

cpp 复制代码
#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

template<class T1, class T2>
class AA    
{
    T1 m_x;
    T2 m_y;
public:
    AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }
    // 非模板友元:友元函数不是模板函数,而是利用模板类参数生成的函数,只能在类内实现。
  // 本质:编译器利用模板参数,帮我们生成了一个友元函数,但是这个函数不是模板函数
    friend void show(const AA<T1, T2>& a)
    {
        cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
    }
};

int main(void)
{
	AA<int,string> a(44,"abcde");
	show(a);
	return 0;
}

5)模板类与函数的组合使用(包括:普通函数,函数模板特化版本,函数模板泛化版本)

模板类可以用于函数的参数和返回值!

cpp 复制代码
#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

template<class T1, class T2>
class AA    // 模板类AA。
{
public:
    T1 m_x;
    T2 m_y;
    AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }
    void show() const { cout << "show()  x = " << m_x << ", y = " << m_y << endl; }
};

// 采用普通函数,参数和返回值是模板类AA的实例化版本。
AA<int, string> func(AA<int, string>& aa)
{
    aa.show();
    cout << "调用了func(AA<int, string> &aa)普通函数。\n";
    return aa;
}

// 函数模板,参数和返回值是的模板类AA。
template <typename T1,typename T2>
AA<T1, T2> func(AA<T1, T2>& aa)
{
    aa.show();
    cout << "调用了func(AA<T1, T2> &aa)特化函数。\n";
    return aa;
}

// 函数模板,参数和返回值是任意类型。
template <typename T>
T func(T &aa)
{
    aa.show();
    cout << "调用了func(AA<T> &aa)任意类型泛化函数。\n";
    return aa;
}

int main()
{
    AA<int, string> aa1(3, "我是一只傻傻鸟。"); //以上三个函数,优先调用普通函数,再次调用特化版本,最后是泛化版本!
    func(aa1);

	AA<double,string> aa2(3.4,"5555"); //特化版本
	func(aa2);
}

6)模板类继承普通类范例:

cpp 复制代码
#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。
class aa
{
public:
	int a_;
	aa(int a) :a_(a) { cout << "调用了AA的构造函数。\n"; }
	void func1() { cout << "调用了func1()函数:m_a=" << a_ << endl;; }

};

template<class T1,class T2>
class bb : public aa
{
public:
	T1 x_;
	T2 y_;	
	bb(T1 x,T2 y,int a): aa(a),x_(x),y_(y){ cout << "调用了BB的构造函数"<<endl;}
	void func2() const { cout << "调用了func2()函数:x = " << x_ << ", y = " << y_ << endl; }
};

int main(void)
{
	bb<int, string> bb(8, "我是一只傻傻鸟。",3);
	bb.func2();
	bb.func1();	
	return 0;
}

学习知识tips:

引用是指针常量的伪装

构造函数一般有两个执行阶段:初始化阶段和赋值阶段;

成员指针运算符 .* 或者 ->* c++特有的

std::is_same //类型萃取相关的函数

integral 美 [ˈɪntɪɡrəl] adj 完整的,n积分

typeid跟sizeof用法意义,有两种写法 typeid(int);

typeid(变量名或者表达式);

7)匿名共用体一般是写在结构体中的

cpp 复制代码
#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

struct st_girl       // 定义超女结构体。
{
	int no;             // 超女编号。
	union              // 定义匿名共同体udata。
	{
		int        a;
		double b;
		char     c[21];
	};
};

int main()
{
	st_girl girl;
        cout<<sizeof(girl)<<endl; 
        //输出是32 = 4 + 4 + 24; 空的union占1个字节;那为什么4个呢,因为得字节对齐
        return 0;
}

8)共用体使用方法:

cpp 复制代码
#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

union udata         // 定义共同体udata。
{
	int        a;
	double b;
	char     c[21];
};

int main()
{
	udata data;

	cout << "sizeof(data)="<< sizeof(data) << endl;

	cout << "data.a的地址是:" << (void*) & data.a << endl;	//输出地址相同
	cout << "data.b的地址是:" << (void*) & data.b << endl;//输出地址相同
	cout << "data.c的地址是:" << (void*) & data.c << endl;//输出地址相同

	data.b = 30; 
	cout << "data.a=" << data.a << endl;
	cout << "data.b=" << data.b << endl;
	cout << "data.c=" << data.c << endl;
}

输出结果:

sizeof(data)=24

data.a的地址是:0x7ffd02aa4860

data.b的地址是:0x7ffd02aa4860

data.c的地址是:0x7ffd02aa4860

data.a=0

data.b=30

data.c=

相关推荐
hummhumm7 分钟前
Oracle 第29章:Oracle数据库未来展望
java·开发语言·数据库·python·sql·oracle·database
wainyz16 分钟前
Java NIO操作
java·开发语言·nio
喵叔哟24 分钟前
重构代码之用委托替代继承
开发语言·重构
lzb_kkk30 分钟前
【JavaEE】JUC的常见类
java·开发语言·java-ee
SEEONTIME30 分钟前
python-24-一篇文章彻底掌握Python HTTP库Requests
开发语言·python·http·http库requests
Zfox_30 分钟前
【Linux】进程信号全攻略(二)
linux·运维·c语言·c++
起名字真南1 小时前
【OJ题解】C++实现字符串大数相乘:无BigInteger库的字符串乘积解决方案
开发语言·c++·leetcode
少年负剑去1 小时前
第十五届蓝桥杯C/C++B组题解——数字接龙
c语言·c++·蓝桥杯
cleveryuoyuo1 小时前
AVL树的旋转
c++
tyler_download1 小时前
golang 实现比特币内核:实现基于椭圆曲线的数字签名和验证
开发语言·数据库·golang