关于C++的零零碎碎

假期了 再回顾下c++的一些书籍,把一些零零碎碎的点记录下来,整理中---

  1. 每个inline函数要在它每一个的编译单位内定义。 所以extern inline *** //error 。因此inline 函数一般声明和定义一起在头文件中。

举例:文件A.h中 声明: extern inline void nothing(); 文件 A.c中定义: void nothing(){}

文件Main.cpp中调用: nothing();

上例 vs2008中 编译器可以通过 ,在G++中是无法通过编译的。

2.const 和 typedef 也是具有内部链接的。

先文件A.c中定义 typedef void T;

再在文件 B.c中定义 typedef int T; 是可以的。

但是这样做A和B两个文件中所定义的类型T就是不同的了。这是一种不好的做法,一般来说这种改名字的定义是在.h文件中定义的,不同的.c文件包含相同的.h文件 编译成不同的.obj文件。这样类型就一致了。

  1. 头文件不能出现的:常规函数的定义 char* wrong(void){},数据定义 int a ,只可能出现extern int a的声明,聚集量定义 short tbl[]={1,2,3},无名的命名空间namespace{}, 导出的模板定义 export template f(T t){}。

4.复制构造函数和赋值=: 复制构造函数:对象未创建,传入参数为本类型对象。赋值=是对象已经建立好了。

举例:自定义_string 中

_string::_string(const _string str ){     m_char=new char[strlen(str.m_char)+1];  //nothing has been built,we have to new      strcpy(m_char,str.m_char);     }_string& _string_::operator=(const _string str){      if(this==&str)            return *this;      delete[] m_char;  //object has already been built, so we can delete      m_char=new char[strlen(str.m_char)+1];      strcpy(m_char,str.m_char);
return *this;
}

5.运算符的重载

举例:operation += 和operation +;

operation += 可以定义为类内的成员函数。而operation +则应该定义为全局的某命名空间的函数。

原因:一般来讲,operation的操作如果是改变这个类型对象的值或状态时,我们可以将它定义为类内的非静态成员函数,其会隐式的传入this指针,改变对象。而想 operation+这样的操作符来讲,会产生一个新值,这样的operation我们就不应该在类内定义了。operation+ 涉及到了三个对象,而operation+=涉及到了两个对 象。

此外类外的操作符重载函数 往往会设成类的友元函数。

6.复制控制

举例:一般用法- complex& complex(const complex& value);

常见错误:1.这个complex 类是一个自定义类型,函数的传入参数必须是类型的引用。如果不是引用类型,传入值类型的话,由于形参的会产生复制的临时队象,这样将会产生无穷的递归。

2.当类的数据成员中含有指针的时候,注意复制控制对指针的操作。智能指针,深层复制,引用计数等等。

7.显式的构造函数 explicit

举例:

class String {private:    int intvalue;    char charvalue;public:    explicit String(int n ):intvalue(n){}};//调用对象    String s1=200;//error 没有显式调用

8.输入输出操作符的重载

举例:

class X{private:    int m_value;public:    int a; int b; int c;public:    X(int value):m_value(value){}    ostream& operator<<(ostream& os){ os<<"this is in class"<<m_value<<endl;; return os;}    ~X(){cout<<m_value<<" game over ~~"<<endl;}    friend ostream& operator<<(ostream&,X&);//设成友元函数};ostream& operator<<(ostream&os, X& x){os<<"this is out of class "<<x.m_value<<endl;return os;}int main(int argc, char* argv[]){    X x(100);      x<<(cout); //打印 this is in class 100  并不是常见的写法    cout<<x;   //打印 this is out of class 100 常见的写法    return 0;}




通过上个例子可以清楚地看到 operatior<< 往往还是定义为类外函数,而且第一个形参是ostream 类型为好,符合一般写法。 这个例子又一次说明了如果重载的操作符并不是针对本类对象的改变,return输出是别的类的对象,那么我们往往将这个操作符定义到类外。

输入举例

istream& operator>>(istream& in ,X& x)// 注意 X类型的引用!!!  写例子时犯错了....{        in>>x.a>>x.b>>x.c; //顺序依次是 a b c     return in;}

9.关于下表操作符

举一个例子即可

class BookIndex{private:    vector<pair<string,int>> vec;    static int index;public:    int operator[](const string& input)    {   for (vector<pair<string,int>>::iterator it=vec.begin();it!=vec.end();++it)        {if(it->first==input)                 return it->second;}        vec.push_back(make_pair(input,index++));        return -1;}};int BookIndex::index=0;int main(int argc, char* argv[]){    BookIndex bl;    cout<<bl["a"]<<endl;    cout<<bl["b"]<<endl;    cout<<bl["c"]<<endl;    cout<<bl["b"]<<endl;    return 0;}

10 C++中的临时对象

(1)在C++中,一些操作很生成临时对象。这些操作是隐式的,所以有时候我们时常因此犯一些错误。比如:调用函数时,

void swap(int a,int b)

{ int temp=a;

a=b;

b=temp;}

这种反复说过的错误就是因为在函数调用时,函数传入的参数对象会生成其临时变量,函数调用完后临时变量销毁,所以没有改变参数对象的值。

(2)另外一种是return

return 返回的也会返回一个临时对象。比如

int add(int a,int b){int c=a+b; return c;} 如果return没有返回一个临时对象,那么 c是函数内局部变量,函数调用完c销毁,我们是无法得到add函数的结果的。

而另一个例子:定义operator+ 的操作来讲

class noreturn{private:    int m_value;    public:    noreturn(noreturn& o)    {       this->m_value=o.m_value;    }    int get(){return m_value;}    friend noreturn operator+(noreturn,noreturn);    noreturn(int value):m_value(value){}};noreturn operator+(noreturn a,noreturn b){    noreturn intemp(a.get()+b.get());    return intemp;}

如果复制函数noreturn(noreturn& o)设为private,那么operator+将会出现错误。原因就在于return出现临时对象,需要调用复制构造函数。之所以要把这一点总结下来是因为,所以在写类似operator+二元操作符的时候千万就不要去new一个对象来保存新值,函数内的new出来的东西不好处理,不容易自主的销毁掉。所以知道了return 会返回一个临时对象就不会犯这种低级错误。

(3)在异常处理中,throw 也是会产生复制的临时对象的。

try{int* x ; ... throw x;}

catch(int *){...} //error,因为此时的x已经销毁了

所以一般以引用的方式来捕捉exception。
原文链接: https://www.cnblogs.com/mirc-c/archive/2012/01/10/2318562.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/39991

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月8日 下午4:39
下一篇 2023年2月8日 下午4:40

相关推荐