首页 > 编程语言 > 详细

让自己习惯C++

时间:2020-02-11 21:36:41      阅读:71      评论:0      收藏:0      [点我收藏+]

  所谓声明式是告诉编译器某个东西的名称和类型,但是略去细节。

  每个函数的声明式揭示其签名式,也就是参数和返回类型,一个函数的签名等同于该函数的类型。

  定义式的任务是提供声明式所遗漏的一些细节,对对象而言,定义式是编译器为此对象拨发内存地点,对function或function template而言,定义式提供了代码本体,对class或class template而言,定义式列出了他们的成员。

  初始化是“给予对象初值的过程”,对用户自定义类型的对象而言,初始化由构造函数执行。

  default构造函数是一个可被调用而不带任何实参者,这样的函数要不没有参数,要不每个参数都有缺省值。copy构造函数被用来“以同型对象初始化自我对象”,copy assignment操作符是被用来从一个同型对象中拷贝值到自我对象,区别在于有没有个新对象被定义。

条款01:视C++为一个语言联邦

  1. C:说到底C++仍是以C为基础。区块,语句,预处理器,内置数据类型,数组,指针统统来自C。
  2. Object-Oreinted C++:这一部分是面向对象设计之古典守则在C++上的最直接实施。类,封装,继承,多态,virtual函数等等...
  3. Template C++:这是C++泛型编程部分。
  4. STL。STL是个template程序库:容器(containers),迭代器(iterators),算法(algorithms)以及函数对象(function objects)...

条款02:尽量以const,enum,inline替换#define

  用#define可能会导致你是用的名称未进入符号表;若#define AA=6,,可能导致目标代码中出现多份6,解决此问题的办法是用const替换#define。

  1. const的好处:
    1. define直接常量替换,出现编译错误不易定位(不知道常量是哪个变量)。
    2. define没有作用域,一旦被#define,则在其后的编译过程中都有效,除非在某处#undef,const有作用域提供了封装性
  2. enum的好处:
    1. 提供了封装性
    2. 编译器肯定不会分配额外内存空间(其实const也不会)
  3. inline的好处:
    1. define宏函数容易造成误用
//define误用举例

#define MAX(a, b) a > b ? a : b

int a = 5, b = 0;
MAX(++a, b) //a++调用2次
MAX(++a, b+10) //a++调用一次

  对const和enum的解释

#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

class Solution {
private:
    unordered_map<int,vector<int>> cache{{1,{1}},{2,{1,2}},{3,{2,1,3}},{4,{2,1,4,3}},{5,{3,1,2,5,4}}};
private:
    vector<int> beautifulArrayCore(int N)
    {
        if(cache.find(N)!=cache.end())
            return cache[N];

        vector<int> res;
        vector<int> oddRes=beautifulArrayCore((N+1)/2);//N个数中共有(N+1)/2个奇数
        vector<int> evenRes=beautifulArrayCore(N/2);//N个数中共有N/2个偶数

        for(auto& i:oddRes)
            res.push_back(2*i-1);
        for(auto& i:evenRes)
            res.push_back(2*i);
        cache[N]=res;
        return res;
    }
public:
    vector<int> beautifulArray(int N) {
        if(N<=0)
            return {};
        return beautifulArrayCore(N);
    }
};

int main()
{
    Solution s;
    vector<int> res(s.beautifulArray(8));
    for(auto i:res)
        cout<<i<< ;
    cout<<endl;
    return 0;
}

class GamePlayer
{
private:
    static const int num=6;//声明该常量——这是一个声明式。in class初始值设定
    int arr[num];//使用该常量
};
//但是c++要求对使用的任何东西提供一个定义式,但是如果是class的专属常量又是static类型,则需特殊
//处理。只要不取他们的地址,可以声明使用他们而无需提供定义式,但是如果取某个class专属常量的地址
//或你不取其地址编译器坚持要看到定义式,则你需要提供一个定义式。
const int GamePlayer::num;//要把此式子放进实现文件而不是头文件;在声明时已经提供初始值,
                            //现在不提供初始值

class GamePlayer
{
private:
    enum{num=6};//编译期间需要一个class常量,但是编译器不允许编译期间完成in class初值设定,用enumerate代替
    int arr[num];//使用该常量
};

宏实现工厂模式

  1. 需要一个全局的map用于存储类的信息以及创建实例的函数
  2. 需要调用全局对象的构造函数用于注册
using namespace std;

typedef void *(*register_fun)();

class CCFactory{
public:
  static void *NewInstance(string class_name){
    auto it = map_.find(class_name);
    if(it == map_.end()){
      return NULL;
    }else
      return it->second();
  }
  static void Register(string class_name, register_fun func){
    map_[class_name] = func;
  }
private:
  static map<string, register_fun> map_; 
};

map<string, register_fun> CCFactory::map_;

class Register{
public:
  Register(string class_name, register_fun func){
    CCFactory::Register(class_name, func);
  }
};

#define REGISTER_CLASS(class_name);   const Register class_name_register(#class_name, []()->void *{return new class_name;});
  1. 对于单纯常量,最好以const对象或enum替换#define。
  2. 对于形似函数宏,最好改用inline函数替换#define。

条款03:尽可能使用const

  • 如果关键字const出现在星号左边,表示被指物事常量。const char *p和char const *p两种写法意义一样,都说明所致对象为常量;
  • 如果关键字const出现在星号右边,表示指针自身是常量。   
const std::vector<int>::interator iter = vec.begin();//作用像T *const, ++iter 错误:iter是const
std::vector<int>::const_iterator cIter = vec.begin();//作用像const T*,*cIter = 10 错误:*cIter是const

  令函数返回一个常量值,往往可以降低因客户错误而造成的意外,而不至于放弃安全性和高效性。

const Rational operator* (const Rational &lhs, cosnt Rational &rhs);

Rational a,b,c;
if((a*b)=c)
    ...//在a*b的成果上调用operator=,实际上是想一个比较动作

  声明为const的成员函数,不可改变non-static成员变量,在成员变量声明之前添加mutable可让其在const成员函数中可被改变。

  不要在const内调用non-const成员函数,因为对象有可能被改动。

  可以在non-const内调用const,因为non-const内本来就可能改动对象,可以调用const。

const_cast<char &>(static_cast<const TextBlock &>(*this))[position];
//static_cast 将TextBlock &转为const TextBlock &;
//const_cast将返回值去掉const约束;

  operator[]返回值类型是引用,因为

char& operator[](size_t pos)
{
  return arr[pos];  
}
a[0]=x;//如果返回值是内置类型,则赋值就不合法,因为C++by value返回对象这一事实意味着改动的其实是a.arr[0]的一个副本!
  1. 将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
  2. 编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量”(conceptual constness)。
  3. 当cosnt和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。

 

让自己习惯C++

原文:https://www.cnblogs.com/tianzeng/p/12296779.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!