p(0) {}//表明sp的构造函数,如果在当前编译语句的

作者: 编程  发布:2019-08-29

C、C : 引用、指针、实例、内部存款和储蓄器模型、namespace,模型namespace

// HelloWorld.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "string.h"
#include "iostream.h"


/**
 * 在C、C  语言中
 *      声名语句中:    声明指针变量用*,声明变量或者常量都不加*。
 *                        譬如函数声明中的参数,返回值类型等。例如类中的字段的声明。
 *        在赋值语句中:  * 表示取值。   &表示取变量的地址,也就是取指针。
 *
 *      class,struct,unit:    也遵循上述原则。另外,
 *                            在使用指针进行变量的访问、方法的调用时,要使用 ->
 *                            在使用实例进行变量的方式、方法的调用时,要使用.
 *                          例如personTest()方法中:
 *                          p是指针,*p就是p所指向的实例。
 *
 *      personTest()测试中的内存模型:
 *     指针p                Value *p ,也可以称为实例
 *     ___________             __________           ___________
 *    |           |           | name     |-------> |Fang JiNuo | *name
 *    |           |  —————>   | age : 23 |         |___________|
 *    |___________|           | address  |         ______________________  
 *                            |__________|-------> | Bei Jing, Haid Dian | *address
 *                                                 |_____________________|
 */
class Person
{
    private:
        char* name;
        int age;
        char* address;
    public :
        char* toString()
        {
            char* ret=name;
            return ret;
        }
        void setAge(int age){
            this->age=age;
        }
        void setAddress(char* address){
            this->address=address;
        }
        void setName(char* name){
            this->name=name;
        }
};

void personTest(){
    Person * p=new Person();
    p->setAddress("Bei Jing, Hai Dian"); // 采用指针的方式赋值
    (*p).setName("Fang JiNuo");          // 采用对象的方式赋值
    (*p).setAge(23);
    printf("show info:n%sn", (*p).toString());
}

void switchTest(){
    int a=23;
    int b=1;
    int c=0;
    char oper=' ';
    switch(oper){
    case ' ':
        c=a b;
    case '-':
        c=a-b;
        break;
    case '*':
        c=a*b;
        break;
    }
    printf("c = %d %c %d = %d", a, oper, b, c);
}

/**
 * C 语言的输入输出
 */
void input_Output_test_c(){
    printf("Hello World!n");
    printf("zhang san, wo cao n");
    int a,b;
    printf("input tow int number, pattern is d, d:n");
    scanf("%d, %d", &a, &b);
    printf("a is %dn",a);
    printf("b is %dn",b);
    printf("a b=%dn",a b);
}

/**
 * C 的输入输出
 * 使用前须求include iostream.h
 */
 void input_Output_test_cpp()

 {

*     // << out1 << out2 << out3 << out4 << endl;
     // endl 代表endline,约等于换行
     char * content=new char;
     cout << "plese input:" << endl;
     cin>> content;
     cout << content << endl;
  }*

/**
 * namespace
 * C 语言不支持。
 * C 支持。
 *
 */
  namespace MyNS
  {
    void namespaceTest(){
      cout << "MyNS namespace invoked" << endl;
    }
  }

  void namespaceTest(){
    cout << "current namespace invoked" << endl;
  }

int main(int argc, char* args[])
{

// input_Output_test_c();
// personTest();
// switchTest();
// input_Output_test_cpp();
namespaceTest();
MyNS::namespaceTest();

    return 0;
}

 

引用、指针、实例、内部存款和储蓄器模型、namespace,模型namespace // HelloWorld.cpp : Defines the entry point for the console application. // #include " stdafx.h " #...

// HelloWorld.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "string.h"
#include "iostream.h"


/**
 * 在C、C  语言中
 *      声名语句中:    声明指针变量用*,声明变量或者常量都不加*。
 *                        譬如函数声明中的参数,返回值类型等。例如类中的字段的声明。
 *        在赋值语句中:  * 表示取值。   &表示取变量的地址,也就是取指针。
 *
 *      class,struct,unit:    也遵循上述原则。另外,
 *                            在使用指针进行变量的访问、方法的调用时,要使用 ->
 *                            在使用实例进行变量的方式、方法的调用时,要使用.
 *                          例如personTest()方法中:
 *                          p是指针,*p就是p所指向的实例。
 *
 *      personTest()测试中的内存模型:
 *     指针p                Value *p ,也可以称为实例
 *     ___________             __________           ___________
 *    |           |           | name     |-------> |Fang JiNuo | *name
 *    |           |  —————>   | age : 23 |         |___________|
 *    |___________|           | address  |         ______________________  
 *                            |__________|-------> | Bei Jing, Haid Dian | *address
 *                                                 |_____________________|
 */
class Person
{
    private:
        char* name;
        int age;
        char* address;
    public :
        char* toString()
        {
            char* ret=name;
            return ret;
        }
        void setAge(int age){
            this->age=age;
        }
        void setAddress(char* address){
            this->address=address;
        }
        void setName(char* name){
            this->name=name;
        }
};

void personTest(){
    Person * p=new Person();
    p->setAddress("Bei Jing, Hai Dian"); // 采用指针的方式赋值
    (*p).setName("Fang JiNuo");          // 采用对象的方式赋值
    (*p).setAge(23);
    printf("show info:n%sn", (*p).toString());
}

void switchTest(){
    int a=23;
    int b=1;
    int c=0;
    char oper=' ';
    switch(oper){
    case ' ':
        c=a b;
    case '-':
        c=a-b;
        break;
    case '*':
        c=a*b;
        break;
    }
    printf("c = %d %c %d = %d", a, oper, b, c);
}

/**
 * C 语言的输入输出
 */
void input_Output_test_c(){
    printf("Hello World!n");
    printf("zhang san, wo cao n");
    int a,b;
    printf("input tow int number, pattern is d, d:n");
    scanf("%d, %d", &a, &b);
    printf("a is %dn",a);
    printf("b is %dn",b);
    printf("a b=%dn",a b);
}

 extern关键字的知情和效果深入  

/******************************************************************************************************************/

/**
 * C 的输入输出
 * 使用前必要include iostream.h
 */
 void input_Output_test_cpp()

extern是多个根本字,它报告编写翻译器存在着贰个变量或许叁个函数,要是在脚下编写翻译语句的近日中从未找到相应的变量恐怕函数,

一、C 智能指针_温馨实现智能指针

 {

也会在脚下文件的末尾也许其它文件中定义

1.选拔一些变量结合new的办法,防止new导致的内部存款和储蓄器泄漏

*     // << out1 << out2 << out3 << out4 << endl;
     // endl 代表endline,也正是换行
     char * content=new char;
     cout << "plese input:" << endl;
     cin>> content;
     cout << content << endl;
  }*

引文一、(主就算实战中的各个场所)

class sp

/**
 * namespace
 * C 语言不协理。
 * C 支持。
 *
 */
  namespace MyNS
  {
    void namespaceTest(){
      cout << "MyNS namespace invoked" << endl;
    }
  }

主干解释:extern可以放手变量大概函数前,以标示变量恐怕函数的定义在别的文件中,提醒编写翻译器遇到此变量和函数时在任何模块中找寻其定义。其余extern也可用来举行链接内定。

{

  void namespaceTest(){
    cout << "current namespace invoked" << endl;
  }

      也正是说extern有七个效果与利益,第贰个,当它与"C"一齐连用时,如: extern "C" void fun(int a, int b);则告知编写翻译器在编写翻译fun这么些函数名时按着C的条条框框去翻译相应的函数名实际不是C 的,C 的平整在翻译那些函数名时会把fun这几个名字变得万象更新,或者是fun@aBc_int_int#%$也说不定是别的,那要看编写翻译器的"性情"了(不一样的编写翻译器选拔的主意不等同),为啥这么做吗,因为C 帮忙函数的重载啊,在这里不去过多的阐释那个主题素材,假诺您风乐趣能够去网络搜寻,相信你能够取得满意的表明!
    第二,当extern不与"C"在一齐修饰变量或函数时,如在头文件中: extern int g_Int; 它的功效正是声称函数或全局变量的成效范围的重大字,其宣称的函数和变量可以在本模块活别的模块中央银行使,记住它是一个宣称不是概念!也正是说B模块(编写翻译单元)假诺援引模块(编写翻译单元)A中定义的全局变量或函数时,它一旦满含A模块的头文件就可以,在编写翻译阶段,模块B纵然找不到该函数或变量,但它不会报错,它会在接连时从模块A生成的指标代码中找到此函数。

private:

int main(int argc, char* args[])
{

2 问题:extern 变量
  在八个源文件里定义了一个数组:char a[6];
  在别的贰个文件里用下列语句进行了声称:extern char *a;
  请问,那样可以吧? 
  答案与分析:
  1)、不得以,程序运转时会告诉你私自访谈。原因在于,指向类型T的指针并不等价于类型T的数组。extern char *a申明的是一个指南针变量实际不是字符数组,因而与实际的定义不相同,进而致使运转时违法访谈。应该将宣示改为extern char a[ ]
  2)、例子分析如下,要是a[] = "abcd",则外界变量a=0x61626364 (abcd的ASCII码值),*a鲜明并未有意义
  显著a指向的空间(0x61626364)未有趣,易并发违法内部存储器访谈。
  3)、那提醒大家,在使用extern时候要严加对应申明时的格式,在其实编制程序中,那样的一无所能司空见惯。
  4)、extern用在变量表明中时常有如此贰个功效,你在*.c文件中声称了八个大局的变量,那么些大局的变量假如要被引述,就献身*.h中并用extern来声明。

         Person *p;

// input_Output_test_c();
// personTest();
// switchTest();
// input_Output_test_cpp();
namespaceTest();
MyNS::namespaceTest();

3 问题:当方面修改extern 函数原型
  当函数提供方单方面修改函数原型时,假设运用方不知情继续套用原本的extern注明,那样编写翻译时编写翻译器不会报错。不过在运营进度中,因为少了照旧多了输入参数,往往会照成系统错误,这种情景相应怎么样缓慢解决?
  答案与深入分析:
  如今产业界针对这种情状的拍卖未有一个很完善的方案,日常的做法是提供方在和睦的xxx_pub.h中提供对外表接口的扬言,然后调用方include该头文件,进而省去extern这一步。以幸免这种错误。
  宝剑有双锋,对extern的施用,不相同的场合应该选用不一样的做法。

public:

    return 0;
}

4 问题:extern “C”
  在C 情形下使用C函数的时候,平日会产出编写翻译器不能够找到obj模块中的C函数定义,从而导致链接退步的图景,应该怎么着消除这种状态吧?

         sp() : p(0) {}//申明sp的结构函数 承接person的无参构造函数       

 

  答案与剖析:
  C 语言在编写翻译的时候为了化解函数的多态难点,会将函数名和参数联合起来生成叁个中间的函数名称,而C语言则不会,由此会导致链接时找不到相应函数的情况,此时C函数就供给用extern “C”进行链接钦定,那告诉编写翻译器,请保持自身的称号,不要给自身生成用于链接的中游函数名。
  上面是叁个正经的写法:
//在.h文件的头上
#ifdef __cplusplus
#if __cplusplus
extern "C"{
 #endif
 #endif /* __cplusplus */ 
 …
 …
 //.h文件甘休的地方
 #ifdef __cplusplus
 #if __cplusplus
}
#endif
#endif /* __cplusplus */ 

         sp(Person *other)

5 问题:extern 函数宣称
  平日见extern放在函数的如今成为函数评释的一片段,那么,C语言的首要字extern在函数的宣示中起什么功能?
  答案与分析:
  借使函数的宣示中包括关键字extern,仅仅是暗暗表示那个函数大概在其余源文件里定义,没有别的功能。即下述多个函数证明没有显然的界别:
extern int f(); 和int f();
  当然,那样的用处照旧有的,正是在前后相继中代替include “*.h”来声称函数,在一些错落有致的品种中,笔者比较习于旧贯在装有的函数证明前增加extern修饰。关于这样做的因由和利弊可知上边包车型地铁这些例子:“用extern修饰的全局变量”

   {

    (1) 在test1.h中有下列注脚:
    #ifndef TEST1H
    #define TEST1H
    extern char g_str[]; // 注脚全局变量g_str
    void fun1();
    #endif
    (2) 在test1.cpp中
    #include "test1.h"
        char g_str[] = "123456"; // 定义全局变量g_str
        void fun1() { cout << g_str << endl; }
    (3) 以上是test1模块, 它的编写翻译和一连都得以通过,尽管大家还应该有test2模块也想使用g_str,只供给在原著件中引用就能够了
    #include "test1.h"

                   cout<<"sp(const Person *other)"<<endl;

     void fun2()    { cout << g_str << endl;    }
    以上test1和test2能够并且编写翻译连接通过,即使你感兴趣的话能够用ultraEdit张开test1.obj,你能够在中间找到"123456"那么些字符串,但是你却不能够在test2.obj里面找到,那是因为g_str是全部工程的全局变量,在内部存款和储蓄器中只设有一份,test2.obj那几个编写翻译单元没有供给再有一份了,不然会在连接时报告再度定义那些张冠李戴!
    (4) 某一个人欢乐把全局变量的扬言和定义放在一同,这样能够免止遗忘了概念,如把地点test1.h改为
    extern char g_str[] = "123456"; // 那年一定于尚未extern
    然后把test1.cpp中的g_str的概念去掉,今年再编写翻译连接test1和test2五个模块时,会报连接错误,那是因为您把全局变量g_str的定义放在了头文件从此,test1.cpp以此模块包括了test1.h所以定义了一回g_str,而test2.cpp也富含了test1.h所以再贰次定义了g_str,那个时候连接器在一而再test1和test2时发掘四个g_str。假使您非要把g_str的概念放在test1.h中的话,那么就把test2的代码中#include "test1.h"去掉 换成:
    extern char g_str[];
    void fun2()   {  cout << g_str << endl;   }
   今年编写翻译器就知道g_str是引自于外界的贰个编写翻译模块了,不会在本模块中再重复定义二个出去,然则本身想说那样做老大不佳,因为您由于无法在test2.cpp中选拔#include "test1.h",那么test1.h中扬言的别样函数你也无力回天利用了,除非也用都用extern修饰,那样的话你光注明的函数将要一大串,况兼头文件的效应正是要给外界提供接口使用的,所以 请记住, 只在头文件中做表明,真理总是这么轻易

                   p = other;

  1. extern 和 static

         }

 (1) extern 表明该变量在别的地点已经定义过了,在这里要运用特别变量.
 (2) static 表示静态的变量,分配内部存款和储蓄器的时候, 存储在静态区,不存款和储蓄在栈上边.

         ~sp()

    static 作用范围是中间连接的关联, 和extern有一点点相反.它和对象自我是分开累积的,extern也是分手累积的,但是extern能够被别的的对象用extern 引用,而static 不得以,只同意对象自己用它. 具体差距首先,static与extern是一对“万枘圆凿”的玩意儿,也即是说extern和static无法同不经常间修饰多个变量;其次,static修饰的全局变量申明与定义同期开展,约等于说当您在头文件中应用static证明了全局变量后,它也同有的时候候被定义了;最后,static修饰全局变量的效用域只好是自己的编写翻译单元,也等于说它的“全局”只对本编写翻译单元有效,别的编写翻译单元则看不到它,如:
    (1) test1.h:
    #ifndef TEST1H
    #define TEST1H
    static char g_str[] = "123456"; 
    void fun1();
    #endif

         {

    (2) test1.cpp:
    #include "test1.h"
    void fun1()  {   cout << g_str << endl;  }
    (3) test2.cpp
    #include "test1.h"
    void fun2()  {   cout << g_str << endl;  }
    以上五个编写翻译单元能够连绵不断成功, 当你张开test1.obj时,你能够在它在那之中找到字符串"123456",同一时间您也得以在test2.obj中找到它们,它们之所以能够连绵不断成功而并未有报重复定义的不当是因为固然它们有同样的剧情,不过存款和储蓄的物理地址并差别等,就像四个例外变量赋了同一的值同样,而这多少个变量分别功用于它们分别的编写翻译单元。 只怕你比较较真,本身私行的追踪调节和测量检验上边的代码,结果你发觉五个编写翻译单元(test1,test2)的g_str的内部存款和储蓄器地址同样,于是你下定论static修饰的变量也足以功能于其余模块,然而自身要告诉您,那是您的编写翻译器在棍骗你,大很多编写翻译器都对代码都有优化作用,以达到生成的目的程序更省去内部存款和储蓄器,实行成效越来越高,当编写翻译器在连接各种编写翻译单元的时候,它会把一样内容的内存只拷贝一份,比如上边的"123456", 位于五个编写翻译单元中的变量都以同一的源委,那么在接连的时候它在内存中就只会存在一份了,要是你把下面的代码改成下边包车型地铁理所当然,你当时就足以拆穿编写翻译器的假话:
    (1) test1.cpp:
    #include "test1.h"
    void fun1()
    {
        g_str[0] = ''a'';
        cout << g_str << endl;
    }

                   cout<<"~sp()"<<endl;

    (2) test2.cpp
    #include "test1.h"
    void fun2()  {  cout << g_str << endl;  }
    (3) void main()     {
        fun1(); // a23456
        fun2(); // 123456
    }
    今年你在追踪代码时,就能意识四个编写翻译单元中的g_str地址并不相同,因为您在一处修改了它,所以编写翻译器被粗鲁的大张旗鼓内存的原来的样子,在内部存款和储蓄器中留存了两份拷贝给七个模块中的变量使用。正是因为static有上述的表征,所以一般定义static全局变量时,都把它座落原版的书文件中实际不是头文件,那样就不会给任何模块变成不供给的新闻污染,一样记住这几个规格呢!

                   if (p)

  1. extern 和const

                            delete p;

   C 中const修饰的全局常量占领跟static同样的特点,即它们只可以功能于本编写翻译模块中,然而const能够与extern连用来声称该常量能够功效于别的编写翻译模块中, 如extern const char g_str[];
    然后在原来的作品件中别忘了定义:     const char g_str[] = "123456"; 

         }

    所以当const单独使用时它就与static一样,而当与extern一同合作的时候,它的表征就跟extern的同等了!所以对const笔者从没什么能够过多的陈述,笔者只是想唤醒您,const char* g_str = "123456" 与 const char g_str[] ="123465"是分裂的, 前边那么些const 修饰的是char *而不是g_str,它的g_str并极其量,它被当做是叁个定义了的全局变量(能够被其他编写翻译单元使用), 所以要是你像让char*g_str遵循const的大局常量的准则,最好这么定义const char* const g_str="123456".

  Person *operator->()//重载->         

 

  {

引文二、(首要偏侧知情和实用)

                   return p;

 

        }

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. extern int i;  
  6. extern void func();  
  7. int _tmain(int argc, _TCHAR* argv[])//typedef wchar_t     _TCHAR;#define _tmain      wmain  
  8. {  
  9.     i = 0;  
  10.     func();  
  11.     return 0;  
  12. }  
  13.   
  14. int i;  
  15.   
  16. void func()  
  17. {  
  18.     i ;  
  19.     cout << "i = " << i << endl;  
  20. }  

};

 

 

    上边代码中变量i和函数func在文书末尾定义,所以变量要求使用extern关键字告诉编写翻译器,变量在别的地方定义。extern int i笔者原先感觉extern i就能够,结果编写翻译器报错,留心想下真的应该,否则编写翻译器不知道i是如何类型的多寡,又怎么能剖断i = 0是还是不是是一个没有错的赋值语句呢?

void test_func(void)

 

{

    那么定义在任何文件中的函数和变量,怎么样通过extern关键字调用吗?

         sp s = new Person();//分配的堆空间只是当作参数字传送递进去(传递给构造函数)了  

    首先,定义在另外文件中的函数和变量,能够应用三种办法调用:

    s->printInfo();

        一、使用头文件调用,那时候,函数和变量必需在头文件中定义和注明。

}

        二、使用extern关键字调用,那时候函数和变量在.cpp恐怕.c文件中定义和表明。

分配的堆空间只是当作参数字传送递进去(传递给构造函数)了,s推行完后调用s的析构函数(局地变量,栈里),析构函数中又释放了内部存储器就从未有过败露了

    看上边七个例证:

后来代码中供给person指针就能够动用sp替代,不用顾忌内部存款和储蓄器泄漏

    devVar.cpp函数中定义:

 

       

/* 相当于:

[cpp] view plain copy

* 1. Person *p = new Person();

 

* 2. sp tmp(p);  ==> sp(Person *other)

  1. #include "stdafx.h"  
  2.   
  3. int i;  

* 3.

 

* 3.1 sp other(tmp);  ==> sp(sp &other2)

    extern.cpp中

标题在于: sp &other2 = tmp; // 错误语法,因为援用不可能对等有时变量                

[cpp] view plain copy

const sp& other2 = tmp; //ok

 

* 或

  1. // extern.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include <iostream>  
  6. using namespace std;  
  7.   
  8. extern int i;  
  9. extern void func();  
  10. int _tmain(int argc, _TCHAR* argv[])//typedef wchar_t     _TCHAR;#define _tmain      wmain  
  11. {  
  12.     i = 0;  
  13.     func();  
  14.     return 0;  
  15. }  
  16.   
  17. void func()  
  18. {  
  19.     i ;  
  20.     cout << "i = " << i << endl;  
  21. }  

* 3.2 sp other(tmp ==> Person*);  ==>sp(Person *other)

 

*/

   编写翻译工程,程序输出:i = 1,这里使用extern关键字表明在别的cpp文件中定义的变量和函数。

sp other = new Person();//编写翻译器优化,直接把2,3部统一为一步

 

 

    #include <filensme> --- 将filename文件中的内容插入到新的公文中。

for (i = 0; i < 2; i )

    deVar.h文件中代码为

                   test_func(other);//这里进行五回会崩溃,原因在于第二回推行完后,把p指向的对象释放了,第一遍再利用该指针自然会奔溃。

[cpp] view plain copy

2.消除办法,引入援引计数,也正是再追加贰个平头成员,当发掘有人引用对象时 该值加1,倘若运用完 减一,若是等于0再自由(解决太早释放难题)

 

class Person {

  1. #include <stdio.h>  
  2.   
  3. int i = 1;  
  4.   
  5. void func()  
  6. {  
  7.     printf("%d",i );  
  8. }  

private:

     函数func修改全局变量i的值并出口。

         int count;

    extern.cpp文件内容为:

public:

[cpp] view plain copy

         void incStrong(){ count ; }     

 

         void decStrong(){ count--; }     

  1. #include "stdafx.h"  
  2. #include <stdio.h>  
  3. #include <iostream>  
  4. using namespace std;  
  5. #include "devVar.h"  
  6. //extern int i;  
  7. //extern void func();  
  8.   
  9. int main(void)  
  10. {  
  11.     for (int x = 0;x < 10; x )  
  12.     {  
  13.         func();  
  14.     }  
  15. }  

         int getStrongCount(){ return count;}

前后相继输出1,2,3,4,5,6,7,8,9,10,这里#include <filname.h> 满含定义在任何头文件中的函数和变量,在来看三个例证。

  Person() : count(0)//代表构造时count值私下认可值是0

   

  {

[cpp] view plain copy

                   cout <<"Pserson()"<<endl;

 

         }

  1. // extern.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include <iostream>  
  6. using namespace std;  
  7.   
  8. extern int i;  
  9. extern int  func(int);//这里extern必得的,函数定义在别的cpp文件中  

         ~Person()

[cpp] view plain copy

         {

 

                   cout << "~Person()"<<endl;

  1. int _tmain(int argc, _TCHAR* argv[])//typedef wchar_t     _TCHAR;#define _tmain      wmain  
  2. {  
  3.     i = 100;  
  4.     func(i);  
  5.     return 0;  
  6. }  

         }

    devVar.cpp文件中剧情为:

         void printInfo(void)

   

         {

[cpp] view plain copy

                   cout<<"just a test function"<<endl;

 

         }

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. int i;  
  6.   
  7. int func(int a)  
  8. {  
  9.     i = a;  
  10.     cout << "i = " << i << endl;  
  11.     return 0;  
  12. }  

};

    那样,一样是出口了i= 100。

class sp

    能够使用extern引用另外cpp文件中定义的函数表明了三个标题:

{

    假使二个工程现编译cpp文件,在把两个目的文件链接成为可试行文件,而多少个或五个文件中,定义了一样的全局变量,那么,程序编写翻译的时候不会报错,因为编写翻译器单独编写翻译每一个文件,在链接可实行文件的时候,由于五个目的文件中带有同样的全局变量,而生成可试行文件的时候,任何文件中定义的全局变量对别的目的文件都是可知的,此时由于变量定义争论而发生错误。看上面的代码:

private:

   

         Person *p;

[cpp] view plain copy

public:

 

         sp() : p(0) {}

  1. // extern.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include <iostream>  
  6. using namespace std;  
  7.   
  8. int i;  
  9. extern int  func(int);//这里extern是必得的函数定义在其余cpp文件中  
  10. int _tmain(int argc, _TCHAR* argv[])//typedef wchar_t     _TCHAR;#define _tmain      wmain  
  11. {  
  12.     i = 100;  
  13.     func(i);  
  14.     return 0;  
  15. }  

         sp(Person *other)

 

         {

devVar.cpp文件中,内容为:

                   cout<<"sp(Person *other)"<<endl;

[cpp] view plain copy

                   p = other;

 

                   p->incStrong();

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. int i;  
  6.   
  7. int func(int a)  
  8. {  
  9.     i = a;  
  10.     cout << "i = " << i << endl;  
  11.     return 0;  
  12. }  

         }

    单独compile任何三个cpp文件都是对的,不过 编写翻译工程,生成可试行文件的时候报错:

         sp(const sp &other)

    1>LINK : D:vctestexternDebugextern.exe not found or not built by the last incremental link; performing full link
1>devVar.obj : error LNK2005: "int i" (?i@@3HA) already defined in extern.obj
1>D:vctestexternDebugextern.exe : fatal error LNK1169: one or more multiply defined symbols found

         {

    原因是:多少个.cpp文件中都定义了全局变量i,变量重复定义了。

                   cout<<"sp(const sp &other)"<<endl;

 

                   p = other.p;

    PS:定义在.h文件中的函数和变量不可能使用extern变量证明,原因是#include <filename>在预编写翻译的时候将.h文件中的内容插入了cpp文件中,因而编写翻译器找获得在别的.h文件中定义的变量大概函数。编写翻译的时候,只编译cpp文件的原委,.h文件时不参预编写翻译,假若使用extern申明在.h文件中定义的变量或许函数,那么注明为extern的变量和函数在其它.cpp文件中找不到,因而前后相继编写翻译的时候就生出了不当。

                   p->incStrong();

 

         }

 

         ~sp()

chapter2,怎么着混合编译C语言和C

         {

    实际支付进度中,C 中会调用C与语言编写的代码,笔者在互联网方面找到一篇写得很好的稿子

                   cout<<"~sp()"<<endl;

   

                   if (p)

   就着地方的例证,笔者使用C语言采取二种办法重写了弹指间。

                   {

   方法一、全局函数和变量在devVar.c文件中贯彻,在extern.cpp文件中使用extern关键字注脚在devVar.c文件中定义的函数和变量。

                            p->decStrong();

   devVar.c文件的代码如下所示:

                            if (p->getStrongCount() == 0)

   

                            {

[cpp] view plain copy

                                     delete p;

 

                                     p = NULL;

  1. #include <stdio.h>  
  2.   
  3. int i = 1;  
  4.   
  5. void func()  
  6. {  
  7.     printf("%d",i );  
  8. }  

                            }

   extern.cpp文件中代码如下所示:

                  }

   

         }

[cpp] view plain copy

         Person *operator->()

 

         {

  1. #include "stdafx.h"  
  2. #include <stdio.h>  
  3. #include <iostream>  
  4. using namespace std;  
  5. //#include "devVar.h"  
  6. //extern int i;  
  7. //extern void func();  
  8.   
  9. extern "C"  
  10. {  
  11.     extern int i;  
  12.     extern void func();  
  13.     //#include "devVar.h"   
  14. }  
  15. int main(void)  
  16. {  
  17.     for (int x = 0;x < 10; x )  
  18.     {  
  19.         func();  
  20.     }  
  21. }  

                   return p;

    所以在C 文件中编写翻译C文件需求使用extern "C"关键字,证明语法如下所示

         }

    extern "C"

};

    {

 

        选用C语言达成的内容

void test_func(sp &other)

    }

{

 

         sp s = other;

    方法二、

         cout<<"In test_func: "<<s->getStrongCount()<<endl;

    在devVar.h文件中达成C代码(即devVar.h作为C语言头文件),在.cpp文件中包涵C语言头文件。

         s->printInfo();

    devVar.h头文件内容为:

         //Person *p = new Person();

   

         //p->printInfo();

[cpp] view plain copy

         //delete p;

 

}

  1. #include <stdio.h>  
  2.   
  3. int i = 1;  
  4.   
  5. void func()  
  6. {  
  7.     printf("%d",i );  
  8. }  

 

    extern.cpp文件内容如下所示

int main(int argc, char **argv)

   

{       

[cpp] view plain copy

         int i;

 

         sp other = new Person();

  1. #include "stdafx.h"  
  2. #include <stdio.h>  
  3. #include <iostream>  
  4. using namespace std;  
  5. //#include "devVar.h"  
  6. //extern int i;  
  7. //extern void func();  
  8.   
  9. extern "C"  
  10. {  
  11.     //extern int i;  
  12.     //extern void func();  
  13.     #include "devVar.h"   
  14. }  
  15. int main(void)  
  16. {  
  17.     for (int x = 0;x < 10; x )  
  18.     {  
  19.         func();  
  20.     }  
  21. }  

         cout<<"Before call test_func: "<<other->getStrongCount()<<endl;

    在那之中,包涵C语言头文件的不二等秘书诀为:

         for (i = 0; i < 2; i )

[cpp] view plain copy

         {

 

                   test_func(other);

  1. extern "C"  
  2. {  
  3.     //extern int i;  
  4.     //extern void func();  
  5.     #include "devVar.h"   
  6. }  

                   cout<<"After call test_func: "<<other->getStrongCount()<<endl;

 

}

    写到这里,楼主又发出了四个疑团,下边包车型地铁例子讲的是C 调用C完结的代码,那尽管是C调用C 编写的代码呢?

         return 0;//main函数推行完后,再次减一,那时就把person对象销毁了

    楼主作了如下改换:

}

    devVar.cpp代码为:   

 

[cpp] view plain copy

  1. 重载*,供上面选取

 

Person& operator*()//重载*,供上面选取 

  1. #include <stdio.h>  
  2.   
  3. int i = 1;  
  4.   
  5. void func()  
  6. {  
  7.     printf("%d",i );  
  8. }  

{//不行使引用,再次回到的是值,就又会去组织对象(有的时候对象,见上述援引章节)              

    extern.c文件代码为

return *p;

[cpp] view plain copy

}

 

/* 少用"Person *"; 用"sp"来代替"Person *"

  1. #include <stdio.h>  
  2.   
  3. extern int i;  
  4. extern void func();  
  5.   
  6. int main(void)  
  7. {  
  8.     int x = 0;  
  9.     for (;x < 10; x )  
  10.     {  
  11.         func();  
  12.     }  
  13. }  

* Person *per;

    单独编写翻译种种文件都通过,链接声称可奉行文件的时候报错:

* 有2种操作: per->XXXx, (*per).XXX

    1>extern.obj : error LNK2019: unresolved external symbol _func referenced in function _main,表明.c文件中extern void func(),依据C编写翻译的平整,获得函数_func,而devVar.cpp文件选取C 编写翻译方式,获得的函数为XX·!_func(具体楼主也不知晓哈),那样链接的时候函数自然找不到,这怎么消除吗?

* sp也理应有那第22中学操作:

    需求在devVar.cpp中,分明调用extern "C"关键字,注明cpp文件中有关代码,必要遵从C的法子来变化,修改devVar.cpp文件如下所示:

* sp->XXX, (*sp).XXX*

   

*/

[cpp] view plain copy

sp other = new Person();

 

(*other).printInfo();

  1.     #include <stdio.h>  
  2.   
  3.     int i = 1;  
  4.   
  5.   
  6. extern "C" void func()  
  7.     {  
  8.         printf("%d",i );  
  9.     }  

 

     此时,除了必要使用extern "C"评释编写翻译的时候利用C方式编写翻译外,.cpp文件中的代码可以遵从C 方式编写,举个例子

4.优化:将count的操作独立出来,单独为多个类,其余类如person直接接轨,就可以操作count的类。

     devVar.cpp依据下边情势写,也是未可厚非的。

 

    

5.优化:为了让智能指针类更通用,应当把类修改为类模版,那样就不局限于在那之中的指针仅针对person。

[cpp] view plain copy

template<typename T>

 

class sp

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. int i = 1;  
  6.   
  7. extern "C" void func()  
  8.     {  
  9.         cout << "i = " << i  << endl;  
  10.     }  

{

private:

         T *p;

}

 

末段就能够完毕, 用"sp<Person>"来顶替"Person *

何况不须要delete,由系统释放

 

/******************************************************************************************************************/

二、C 智能指针_轻量级指针

count 不是原子操作,所以在十二线程的动静下是不安全的

故而引进轻量级指针(保障原子操作,保险操作count值线程安全):

 

1.选拔安卓提供的轻量级智能指针的代码:

using namespace android::讴歌RDXSC;//使用安卓命名空间下的CRUISERSC命名空间

 

class Person : public LightRefBase<Person>

{//钦命模版参数为person

public:

         Person() {

                   cout <<"Pserson()"<<endl;

         }

         ~Person()

         {

                   cout << "~Person()"<<endl;

         }

         void printInfo(void)

         {

                   cout<<"just a test function"<<endl;

         }

};

 

 

2.被调用的安卓RefBase.h中的部分代码:

template <class T>

class LightRefBase

{

public:

    inline LightRefBase() : mCount(0) { }

    inline void incStrong(__attribute__((unused)) const void* id) const {

      __sync_fetch_and_add(&mCount, 1);//__sync_fetch_and_add是原子操作

}

    inline void decStrong(__attribute__((unused)) const void* id) const {

        if (__sync_fetch_and_sub(&mCount, 1) == 1)

  {//__sync_fetch_and_sub是原子操作

            delete static_cast<const T*>(this);

         }

}

 

3.瞩目轻量级指针只是对count的操作是线程安全的,可是对于操作的靶子即智能指针照旧不安全的,四线程情状下只可以和煦来有限帮忙智能指针的应用是线程安全的,即智能指针指向的靶子的操作是线程安全的。

 

为啥叫轻量指针,是因为代码简单,使用方便。

/******************************************************************************************************************/

三、C 智能指针_弱指针的引进

轻量指针,代码轻巧,使用方便,可是

当有五个智能指针相互引用的时候,由于进行完引用计数不为零,就不能够释放,会招致内部存款和储蓄器泄漏:

 

/* 假使目的里包括别的对象成员:

 * 构造时: 先构造别的对象成员, 再组织对象自己

 * 析构时: 顺序刚好相反

 */

void test_func()

{

         /* 1. 对于 new Person()

          * 1.1 Person对象里的father先被组织

          * 1.2 Person对象里的son被协会

          * 1.3 Person对象自己

          * 2. Person对象的指针传给"sp<Person> father"

          *    导致: sp(T* other) 被调用

          *    它增添了这些Person对象的引用计数(今后此值等于1)

          */

         sp<Person> father = new Person();

 

         /* 1. 对于 new Person()

          * 1.1 Person对象里的father先被组织

          * 1.2 Person对象里的son被协会

          * 1.3 Person对象自己

          * 2. Person对象的指针传给"sp<Person> son"

          *    导致: sp(T* other) 被调用

          *    它扩张了这几个Person对象的援用计数(现在此值等于1)

          */

         sp<Person> son = new Person();

 

         /* 它是多少个"=" : this->son = son

          * "="被重载, 它会再一次追加该Person对象的援用计数

          * 所以son对应的Person对象的援引计数扩大为2

          */

         father->setSon(son);

 

         /* 它是八个"=" : this->father = father

          * "="被重载, 它会再一次追加该Person对象的援引计数

          * 所以father对应的Person对象的援用计数扩展为2

          */

         son->setFather(father);

 

         /* 当test_func施行完时, father和son被析构

          * 1. 先看father:

          *    ~sp(): decStrong, 里面会将计数值减1 , father对应的Person的计数值等于1, 还没等于0, 所以没有delete

          * 2. 对于son:

          *    ~sp(): decStrong, 里面会将计数值减1 , son对应的Person的计数值等于1, 还没等于0, 所以未有delete

          */

}

 

 

对此交叉援引导致内部存款和储蓄器泄漏的主题材料,假诺四个指针是弱援引,约等于不扩大对方的援用计数值,那么就不会促成内部存款和储蓄器泄漏,由此只可以援引弱指针(弱引用)技能减轻这些标题,

 

强指针(强引用):A指向B,A决定B的生死

弱指针(弱援引):A指向B,A不可能说了算B的生育养老医治出殡和埋葬

/******************************************************************************************************************/

四、C 智能指针_强弱指针的落到实处与应用

强弱指针的兑现:

参预引用计数mWeak成员并提供加减操作,同不经常候参与flag成员代表近日是强照旧弱,具体贯彻见安卓源码.

 

1.源码申明:

I、在RefBase.h中的class RefBase中成员指针指向weakref_impl,也正是强弱指针的贯彻,weakref_impl继承于weakref_type(操作成员的抽象类),也等于说weakref_impl正是切实可行的落到实处类。

切实也得以说,

强弱指针的完结重视是参加援引计数mWeak成员并提供加减操作,同一时候参与flag成员表示方今是强依旧弱

再将强弱指针的兑现抽象出抽象类,具体贯彻类weakref_impl继承weakref_type抽象类,并在RefBase.h中的class RefBase中定义指向weakref_impl的指针。

 

II、那样完成的来由:

a.头文件中不想见见个人成员,只想见到接口,则把接口抽象出来为抽象类(放在头文件中),然后剩下的单身为落实类(放在cpp文件中),完毕类承袭抽象类,抽象类对外。

b.注重对象的时候,最棒依赖指针,因为直接重视对象,当指标产生变化就可以随之发生变化,指针只占多个字节就不会跟着变化,对空中布局尚未影响

 

2.强弱指针的利用:

I、使用安卓里现存的,

头文件:

system/core/include/utils

system/core/include/cutils

cpp:

system/core/libutils/RefBase.cpp

makefile:

%.o : %.cpp

         g -c -o $@ $< -I include //-I include表示包蕴当前目录下的include目录

//查找头文件不会递归的往子目录查找,所以依然这里加要么代码中加多目录名/XXX.h

 

例:

int main(int argc, char **argv)

{       

         wp<Person> s = new Person();//弱指针

//s->printInfo(); /* 出错, wp未有重载"->", "*" */

         //(*s).printInfo(); /* 出错, wp未有重载"->", "*" */

 

         sp<Person> s2 = s.promote();//升高为强指针,那样就足以调用了 

    if (s2 != 0) {

                   s2->printInfo();

         }

         return 0;

}

 

II、使用弱指针能够缓慢解决交叉引用导致内部存款和储蓄器泄漏的主题素材,可是想行使引用的指标里的函数,就亟须先进级为强指针才方可调用

#include <iostream>

#include <string.h>

#include <unistd.h>

#include <utils/RefBase.h>

 

using namespace std;

using namespace android;

 

class Person : public RefBase

{//继承RefBase

private:

         char *name;   

         wp<Person> father;

         wp<Person> son;

public:

         Person() {

                   cout <<"Pserson()"<<endl;

         }

         Person(char *name) {

                   cout <<"Pserson(char *name)"<<endl;

                   this->name = name;

         }

         ~Person()

         {

                   cout << "~Person()"<<endl;

         }

         void setFather(sp<Person> &father)

         {

                   this->father = father;

         }

         void setSon(sp<Person> &son)

         {

                   this->son = son;

         }

         char *getName(void)

         {

                   return name;

         }

         void printInfo(void)

         {

                   sp<Person> f = father.promote();

                   sp<Person> s = son.promote();

                  

                   //cout<<"just a test function"<<endl;

                   cout<<"I am "<<name<<endl;

                   if (f != 0)

                            cout<<"My Father is "<<f->getName()<<endl;

                   if (s != 0)

                            cout<<"My Son is "<<s->getName()<<endl;

         }

};

 

/* 假使目的里满含其余对象成员:

 * 构造时: 先构造别的对象成员, 再布局对象自己

 * 析构时: 顺序刚好相反

 */

void test_func()

{

         /* 1. 对于 new Person()

          * 1.1 Person对象里的father先被组织

         * 1.2 Person对象里的son被组织

          * 1.3 Person对象自己

          * 2. Person对象的指针传给"sp<Person> father"

          *    导致: sp(T* other) 被调用

          *    它扩张了这几个Person对象的引用计数(现在此值等于1)

          */

         sp<Person> father = new Person("LiYiShi");

 

         /* 1. 对于 new Person()

          * 1.1 Person对象里的father先被组织

          * 1.2 Person对象里的son被协会

          * 1.3 Person对象自己

          * 2. Person对象的指针传给"sp<Person> son"

          *    导致: sp(T* other) 被调用

          *    它增添了那一个Person对象的援用计数(今后此值等于1)

          */

         sp<Person> son = new Person("LiErShi");

 

         father->setSon(son);

         son->setFather(father);

         father->printInfo();

         son->printInfo();

}

int main(int argc, char **argv)

{       

         test_func();

         return 0;

}

 

本文由9159.com发布于编程,转载请注明出处:p(0) {}//表明sp的构造函数,如果在当前编译语句的

关键词: 9159.com