C++进阶学习
头文件的防卫式声明
#ifndef MYCLASS
#define MYCLASS
Header file content
#endif
成员函数的保护
- 如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加 const 修饰。例如不要将函数
void Func1(int x)
写成void Func1(const int x)
。 - 如果参数作为输出参数,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加 const 修饰,否则该参数将失去输出功能(因为有 const 修饰之后,不能改变他的值)。
- 如果参数作为输入参数,可以防止数据被改变,起到保护作用,增加程序的健壮性,建议是能加const尽量加上
int getToValue() const //此处需要加入const,防止shu'j
{
return m_nTo; //this->m_nTo
}
返回值优化
return by reference 的情况包括一个value加到另一个value的情况,不适用于两个value相互作用产生新的value的情况,正如黄色内的内容
return by reference 不需要知道接收者是以reference形式接收的
特殊的重载操作符
<< 不能写为成员函数,只能写全局函数,因为cout不能识别复数类型
inline complex
conj (const complex& x){
return complex(real(x) , -imag(x));
}
#include <iostream>
ostream& //防止第二种情况的发生,需要“cout<<c1”的类型为cout才能接收第二个conj
operator << (ostream& os , const complex& x){ //ostream没有const因为
//向cout内传入数据就是在改变cout
return os << '(' <<real(x)<<','<<imag(x)<<')';
}
int main()
{
complex c1(2 , 1);
cout<<conj(c1);
cout<<c1<<conj(c1); //②
}
Inline函数
Inline函数的使用
如果是在类中,函数的如果在类定义的时候进行定义,那么,加不加关键字 inline 并没有什么异样,因为,这样的函数都会被默认为是内联函数。
详细:C++经验(十一)-- (inlining)内联函数的使用_slowlytalk的博客-CSDN博客
三种特殊的函数
//构造函数
inline
String::String(const char* cstr = 0){//参数为常量指针
if(cstr){
m_data = new char[strlen(cstr) + 1];//"+1"的原因是字符串最后还有一个 结束位
strcpy(m_data , cstr);
}
else{
m_data = new char[1];
*m_data = '\0';
}
}
//析构函数
inline
String::String(){
delete[] m_data;
}
//拷贝构造函数
inline
String::String(const String& str){
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data , str.m_data);
}
//拷贝赋值函数
inline
String& String::String operator=(const String& str){
if(this == &str){
return *this; //监测自我赋值,
}
delete[] m_data;
m_data = new char[strlen(strlen m_data) + 1];
strcpy(m_data , str.m_data);
return *this;
}
内存管理
若使用array new 则一定要使用array delete
String *p = new String[3];
...
delete[] p; //因为delete的数组所以要有[],否则无法彻底清除
堆和栈
class Complex {....}
...
{
Complex c1(1,2);//c1所占用的空间来自于Stack
Complex* p = new Complex(3);//p是个临时对象,空间是从Heap的分配而来的
}
Stack的生命期结束之后清理,也是auto object
static Stack的生命在作用域结束之后仍然存在,在函数结束后才会结束
global object 在类结束后再消失
delete:先调用dtor(析构函数)后释放memory
new:先分配memory 后调用ctor(构造函数)
static
一般常量类型(未被static
修饰)、引用类型,在类内部即可实现初始化,在类外实现初始化的必定是static
类型(当然一部分的静态成员,也即同时又是const和integral type的,可在类内初始值设定,这一语法特性并非为所有的编译器所支持,所以一种推荐的做法,即是凡是static类型的,我们总在类外进行初始化,哪怕它在类内已进行初始值设定,只要在类外初始化时不修改其值):
int Test::si = 0;
const int Test::sci = 1;
const double Test::scd = 99.0;
函数模板
遇到不能立刻确定的数据和函数类型,可以用function template 来暂时定义。
template <class T>
inline
const T& min(const T& a , const T& b){
return b < a ? b : a;}
Composition 表示has-a
template <class T>
class queue{
protected:
deque<T> c;//引用了别的类的数据
};
class deque{
protected:
Itr<T> star;// 同上
Ttr<T> finish;
T** map;
unsigned int map_size;
};
struct Ttr{
T* cur;
T* first;
T* last;
T** node;
};
组合下的构造和析构:
构造顺序为由内而外,析构为由外而内
Delegation Composition by reference
vector 的一些基础操作
向尾部加入元素时由两种函数,一个是push_back(),另一个是emplace_back()
- push_back 可以接收左值也可以接受右值,接收左值时使用拷贝构造,接收右值时使用移动构造
- emplace_back 接收右值时调用类的移动构造
- emplace_back 接收左值时,实际上的执行效果是先对传入的参数进行拷贝构造,然后使用拷贝构造后的副本,也就是说,emplace_back在接收一个左值的时候其效果和push_back一致!所以在使用emplace_back 时需要确保传入的参数是一个右值引用,如果不是,请使用std::move()进行转换
一些库函数的练习
String
class String
{
public:
String(const char* cstr = 0);//构造函数的声明
String(const String& str);//构造拷贝函数
String& operator=(const String& str);//拷贝赋值函数
~String();
char* get_c_str() const{return m_data;}//用于cout的函数
private:
char* m_data;
}
//构造函数
inline //建议作为内联函数,节省空间
String::String(const char* cstr = 0)
{
if(cstr){
m_data = new char[strlen(cstr) + 1];
strcpy(m_data , cstr);
}else{//未指定初值
m_data = new char[1];
*m_data = '\0';
}
}
//析构函数
inline
String::~String()
{
delete[] m_data; //使用array new所以要用delete array
}
//拷贝构造函数
inline
String::String(const String& str)
{
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data , str.m_data);
}
//拷贝赋值函数
inline
String& String::operator(const String& str)
{
if(this == &str){
return *this;//自我
}
delete[] m_data;
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data , str.m_data);
return *this;
}
STL
体验STL库中模板的组成,一个模板可能是由好几个模板相互叠加而形成的
#include <vector>
#include <algorithm>
#inlcude <functional>
#inlcude <iostream>
using namespace std;
int main(){
int ia[6] = {27 , 210 , 12 , 47 , 109 , 83};
vector<int , allocator<int>> vi(ia , ia + 6);//第二个参数可以不写,因为默认分配
cout<<count_if(vi.begin() , vi.end() , not1(bind2nd(less<int>() , 40)));
return 0;
}
STL容器
#include <vector>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio> //snprintf()
#include <iostream>
#include <ctime>
#include <algorithm> //sort()
namespace jj02
{
void test_vector(long& value)
{
cout << "\ntest_vector().......... \n";
vector<string> c;
char buf[10];
clock_t timeStart = clock();
for(long i=0; i< value; ++i)
{
try {
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));
}
catch(exception& p) {
cout << "i=" << i << " " << p.what() << endl;
//曾經最高 i=58389486 then std::bad_alloc
abort();//捕捉到错误后及时退出程序
}
}
cout << "milli-seconds : " << (clock()-timeStart) << endl;
cout << "vector.max_size()= " << c.max_size() << endl; //1073747823
cout << "vector.size()= " << c.size() << endl;
cout << "vector.front()= " << c.front() << endl;
cout << "vector.back()= " << c.back() << endl;
cout << "vector.data()= " << c.data() << endl;
cout << "vector.capacity()= " << c.capacity() << endl << endl;
string target = get_a_target_string();
{
timeStart = clock();//记录第一次时间戳
auto pItem = find(c.begin(), c.end(), target);//返回类型为iterator
cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl;
//记录事件差
if (pItem != c.end())
cout << "found, " << *pItem << endl << endl;
else
cout << "not found! " << endl << endl;
}
{
timeStart = clock();
sort(c.begin(), c.end());
cout << "sort(), milli-seconds : " << (clock()-timeStart) << endl;
timeStart = clock();
string* pItem = (string*)::bsearch(&target, (c.data()),
c.size(), sizeof(string), compareStrings);
cout << "bsearch(), milli-seconds : " << (clock()-timeStart) << endl;
if (pItem != NULL)
cout << "found, " << *pItem << endl << endl;
else
cout << "not found! " << endl << endl;
}
c.clear();
test_moveable(vector<MyString>(),vector<MyStrNoMove>(), value);
}
}
#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio> //snprintf()
#include <algorithm> //find()
#include <iostream>
#include <ctime>
namespace jj03
{
void test_list(long& value)
{
cout << "\ntest_list().......... \n";
list<string> c;
char buf[10];
clock_t timeStart = clock();
for(long i=0; i< value; ++i)
{
try {
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));
}
catch(exception& p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock()-timeStart) << endl;
cout << "list.size()= " << c.size() << endl;
cout << "list.max_size()= " << c.max_size() << endl; //357913941
cout << "list.front()= " << c.front() << endl;
cout << "list.back()= " << c.back() << endl;
string target = get_a_target_string();
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl;
if (pItem != c.end())
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl;
timeStart = clock();
c.sort();
cout << "c.sort(), milli-seconds : " << (clock()-timeStart) << endl;
c.clear();
test_moveable(list<MyString>(),list<MyStrNoMove>(), value);
}
}
标签:const,String,C++,char,深入,str,include,data,候捷
From: https://www.cnblogs.com/zdyCode/p/18129149