Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2571503
  • 博文数量: 315
  • 博客积分: 3901
  • 博客等级: 少校
  • 技术积分: 3640
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-08 15:32
个人简介

知乎:https://www.zhihu.com/people/monkey.d.luffy Android高级开发交流群2: 752871516

文章分类

全部博文(315)

文章存档

2019年(2)

2018年(1)

2016年(7)

2015年(32)

2014年(39)

2013年(109)

2012年(81)

2011年(44)

分类: C/C++

2012-02-27 23:15:22

C++学习笔记1:
    1.编译型和解释型的区别:
    解释型:像java,python,shell等解释型语言在运行过程中,由解释器边读程序边翻译为机器代码,然后执行,中间“略去“了编译和链接的环节,但是不断的和解释器现场进行交互,所以效率就大大的降低了;对于大规模的软件设计就不符合效率规范了;
    编译型:像c,c++等部分高级语言采用的自然就是编译型了,由编译器直接翻译,链接成为可执行的二进制文件(二进制代码),然后再启动文件,这样可执行文件就可以脱离编译器,直接运行了,效率大大提高;C++要体现高性能,当然也就采用了编译型这种方式了。
    以上就是编译型和解释型的核心的区别了,至于具体的机制比这个要复杂多了,比如如何翻译成为机器码,过程中有何区别等等。对于如今cpu的超高性能来说,是否还具有这么大的区别了?

    2.C++编程的操作流程(有必要了解下,虽然你已经很熟悉了):
    a>程序员编写的程序---源程序(source code),对于c++来说是.cpp后缀
    b>程序编译后成为目标代码(object code),一般以.obj为后缀,这时候的目标代码还不能运行,因为这只是程序片段,我们包括的头文件---库文件还没有链接到程序中,需要的库函数,宏变量等数据还没有让他们关联起来;
    c>目标代码(机器代码)经过链接(link)将目标代码整合成可执行文件,c++后缀是.exe(windows)下,在linux中,我们可以任意定义可执行文件的格式,可以没有后缀,本身后缀对于文件来说只是个标识而已;但是在linux中c++源文件需要注意格式,否则编译器不知道你源文件是什么格式,不知道如何去调用相应的操作;
    3.关于“名空间“的问题?
    名空间说白了就是为了解决命名冲突而设计的一种模式;比如我们使用库文件的同时可能会定义自己的函数,操作符等等,如果名字和库提供的相同,那么编译器就不知道怎么办了,所以我们冠以std::cout来表示cout是标准库中的cout,如果是我们自己定义的编译器也会默认加上前缀;
    我记得在c和c++混编的时候,就有个问题?就是函数名冲突了,你的c和c++程序都定义了一个相同的函数名称,而且参数也一样;但运行时不会有问题,这就是他们在编译后的函数名已经完全不同了。
    4.模块的内聚性和外联性的概念?
    内聚性:就是模块内部所涉及的功能越单一越好,不会因为该模块的改变而引起其他模块的改变;
    外联性:就是模块之间的联系越少越好,外联性少,模块独立性就强,更容易修改和分工的细化;
    5.结构化程序设计和对象化程序设计(Structured Programming && Objectified Progarmming)
    结构化程序设计:主要体现在过程的功能划分过程内部的编写规则上,因此它是一种规范的过程化程序设计思想;
    对象化程序设计:本质上还是过程化的,不过某些数据关系被提取出来,成为一个类(对象),可以带来模块的可重用性;
    当然里面还有很多概念,看的头晕了;对象的程序设计由建立起层次结构的抽象数据类型的规范,从相互依赖的关系走向互不影响的合作关系,这就是基于对象的程序设计;
    比如在c中,我们有很多函数,很多变量,而有些是我们需要经常使用的,我们每次都需要去调用它去实现一个我们自己的功能函数,但是如果你发现你需要取修改被调用的某个程序的名字或者参数,那么你的功能函数也需要去改变,这样需要改变两处岂不是很麻烦;如果你利用c++的类的机制,你要实现自己的功能模块的时候只需要取继承下,即使要修改也只需要修改被继承的“父类“,而子类不需要动,同时可以再子类中增加自己特殊的功能,达到代码的高度重用性;当然这只是其中一部分好的特性,还有很多优秀的品质!

C++学习笔记2:
    C++中的向量
  vector在C++中是很有用的东西哦,由于它不像数组那样事先定义大小,它可以初始指定大小,也可以不用指定;所以在数据添加到向量的时候,vector会自动扩展,当然这种扩展必然会增加向量的操作负担,影响内存的性能;对于不是很复杂的数据可以采用它;
  vector有四种定义:
    vector a(10); //不带初始化定义
    vector b(10, 1); //带初始化定义
    vector c(b); //利用向量产生向量--“克隆“
    vector d(b.begin(), b.begin() + 3); //标识把向量b的0-2个元素用了定义和赋值向量
范例:  
//=====================================
// vector.cpp
// 关于向量的操作;向量就是一个容器;
// 向量有“遍历器“,就像一个指针“游走“;
// 向量自由扩充;
//=====================================
#include
#include

using namespace std;

int main(int argc, const char *argv[])
{
    int a[4] = {23, 2, 5, 6};
    vector va(a, a + 4);
  
    //vector::iterator it; //it 就像字符"指针"一样;
    for(vector::iterator it = va.begin(); it != va.end(); ++it)
        cout << *it << " ";
    cout << endl;

    //operator
    va.push_back(45);
    va.clear();
    va.resize(3); //调整元素个数;多去少补,其值随机;
    va.assign(4, 2); //重分配

    for(vector::iterator it = va.begin(); it != va.end(); ++it)
        cout << *it << " ";
    cout << endl;


    return 0;
}

C++学习笔记3:   
    C++类
  到类了,类是C++之所以发展火热的主要原因之一;
我们都知道在C语言中,有结构体的概念,但是结构体中不能有成员函数,是吧,但是可以在结构体中存放函数指针,即使如此,C语言这种利用函数指针来作为存放成员变量的方式不能称之为成员函数,我是这样理解的!因为我们在作bootloader的时候,就可以利用数组的方式来存放函数,实现注册和取消注册函数的这样一个功能,就是利用存放函数指针的方式,所以想到了这个地方...有必要理解清楚他们不同的工作机制。
  书中还谈到了类的成员函数放在类内部或者外部定义的时候,它们各自的性能差异;这就必须想到内联了,学C的时候,也有这块,内联可以大大提升代码的编译速度,而一旦生成可执行代码的时候,我认为性能差异不会太大;C++内联是怎么回事呢?当成员函数在类内部定义的时候,那么它将被编译器视作内联函数,但这是对于那种特简单的函数来说的,如果函数中带循环呀,或者其他很花费时间的代码,那作不作为内联,就说不准了。而在类外部定义的时候编译器不会做这种处理;当然你可以申明此函数为内联函数inline即可;
  这里还有就是类的成员函数和普通函数是不同的,不同因为成员函数是和类邦定在一起的;也就是说是“属于这个类的”这样你在其他的类中定义一模一样的函数也没问题,前提是你的前缀是不同的类;理解的时候可以参考C的结构体,类是由结构体演变而来,所以其实里面的成员函数啊,变量啊之类的都是结构体成员是吧,所以函数自然就演变成为“成员函数了”,也不奇怪!
  对了,还有一个点:java,C++有时候会去“羡慕”java,我们在初学C++的时候可能很容易通过类比C的结构体来书写正确的类---带分号,成员函数内部定义则不需要了,申明还是要的;而java不管是类或者成员函数都不需要,所以就避免了程序员写错,这点要注意;如果你学习国Qt,你的印象会更深,Qt就是和C++类似的,所以练习多了就好了;呵呵!慢慢的把C++这本书看完,在入职之前过一遍吧。
  以后就会专注于三门语言,学好它,走到哪里都不怕!相信自己...希望我的朋友们都能过得很开心...

C++学习笔记4:
p, li { white-space: pre-wrap; }

/*file: leapYear.cpp

* 由leapyear来引申简单笔记,主要是类的相关!

*

*/

#include

#include

#include

#include

using namespace std;

class Date{

//以下变量默认私有

int year;

int month;

int day;

public:

Date(){

//year = 1998; //useless?

//month = 12;

//day = 12;

cout << "Construct....\n";

}

~Date(){

cout << "Destruct...\n";

}

Date(int y, int m, int d){ //构造函数重载

year = y;

month = m;

day = d;

}

//===============================================================

void set(int y, int m, int d);

/*

引用规避了指针的风险,对引用不管怎么赋值都是安全的

int &b = a;

int *p = a;

在程序的应用中,可能会不小心就使用p = 1;而不是*p = 1;这样的赋值语句,而前者直接改地址值的行为是很危险的,因为0x1这个地址可能存放的是重要数据,禁止读写的区域。而引用就不会有这个问题

*/

//void set(string s);

void set(string &s); //重载,同时传递字符串的引用;

bool isLeapYear() const; //常成员函数不允许改变对象的值;

void printDate() const;

//===============================================================

//申明为friend表明这是“友元”,既然是友元,就可以访问类的私有成员变量了。

//Date operator+(const Date& a, const Date& b);

friend Date operator+(const Date& a, const Date& b);

friend Date add(const Date& a, const Date& b);

};

void Date::set(int y, int m, int d)

{

year = y;

month = m;

day = d;

}

void Date::set(string &s)

{

year = atoi(s.substr(0, 4).c_str());

month = atoi(s.substr(5, 2).c_str());

day = atoi(s.substr(8, 2).c_str());

}

bool Date::isLeapYear() const

{

return (year%4 == 0 && year%100 != 0) || (year%400 == 0);

}

inline void Date::printDate() const

{

cout << setfill('0');

cout << setw(4) << year << '-' << setw(2) << month << '-' << setw(2) << day << " ---";

cout << setfill(' ');

}

Date operator+(const Date& a, const Date& b)

{

Date s;

s.set((a.year + b.year), (a.month + b.month), (a.day + b.day));

return s;

}

Date add(const Date& a, const Date& b)

{

Date s;

s.set((a.year + b.year), (a.month + b.month), (a.day + b.day));

return s;

}

int main(int argc, const char *argv[])

{

//===============================================================

//Date *dt = new Date; //can work

Date *dt = new Date(2000, 12, 6); //can work

//这里创建了一个类对象实例,所以显示调用了构造函数;在整个程序结束之后,这个对象才会被销毁;所以我的测试结果中最后还有一个析构函数被调用;

//所以两种方式创建对象的形式不同,其原理也不同!

Date dtt(2000, 12, 6);

//dt->set(2000, 12, 6);

//dt->set("2000-12-06"); //如果原来的参数是一个引用;那么这样会出错的;应该是:string ss = "2000-12-06"; string sq = &ss;

string ss = "2000-12-06";

string &sq = ss;

//dt->set(ss); //can work

dt->set(sq);

if(dt->isLeapYear()){

dt->printDate();

cout << "leape year!\n";

}

free(dt);

//===============================================================

#if 1

Date *aa = new Date(2000, 12, 6); //can work

Date *bb = new Date(2000, 12, 6); //can work

//const Date &a = *aa; //传递引用

//const Date &b = *bb;

//operator+(a, b).printDate();

//(a + b).printDate(); //这种方式默认会调用add函数;

//add(a, b).printDate();

//构造函数在打印之前调用,在我们传入*aa之后才创建的对象;

//在传入对象之前没有调用构造函数,之后立即调用析构函数;

operator+(*aa, *bb).printDate();

(*aa + *bb).printDate(); //这种方式默认会调用add函数;

add(*aa, *bb).printDate();

free(aa);

free(bb);

Date nopa; //调用无参构造函数;如果无无参构造函数,而定义了有参构造函数,此用法会报错的!
nopa.set(2006, 12, 23);
nopa.printDate();

#endif

return 0;

}

//===================结果测试===================================

/*

2000-12-06 ---leape year!

Construct....

4000-24-12 ---Destruct...

Construct....

4000-24-12 ---Destruct...

Construct....

4000-24-12 ---Destruct...

Destruct...

*/

//===================经验之谈(C++程序设计)====================

//设计函数的时候,参数若为类类型,则一般都用引用类型;若为内部数据类型,则不用引用类型,这是重要的经验之谈;

//我们在设计operator+操作符函数的时候,在内部定义了局部的类对象,这是不太好的习惯,会无端造成内存空间泄露;

//还有一个问题是关于流的问题:<<返回的流的引用,而不是对象的引用了,这是因为返回流的引用对于<<来说符合要求,而如果<<操作的是非引用型的流,那么将产生一种基于设备的流的复制,这样也就是临时有了一个符合的操作,显然这种复制品慢了很多,性能自然就下降了!

//后面还有一个增量符的问题:我估计用的地方不会太多,不过要知道增量符分为前增量符和后增量符的差别;其实看看就明白,在c中我们知道定义一个整型变量a,赋值后,让其自增++,然后是不能作为左值的,其实这个后增量符也是如此,一旦自增过,整体在自增就会报错了。其它好像也没啥很重要的;这些都是细节!

//这是关于成员操作符的问题:前面说过成员函数,现在说成员操作符了,你就知道其实它就是在类内部实现函数的定义;以前还不太懂,现在好理解多了;和一般操作符区别就是,它省略了+之前的那个对象的参数,因为在内部嘛,所以我们就省略了第一个参数,之间使用类的成员变量来作为第一个参数;就是这样:

//class Date{

// int year;

// Date operator+(const Date& b){

// Date d;

// d.set(year + b.year);

// return d;

// }

//};

//静态成员{静态数据成员和静态成员函数,静态数据成员和在C语言,功能类似,下一次是上次的保存值+相关操作后的结果;在类中的解释就是:

//只维持在一个对象中的一份拷贝;

//对于静态成员函数来说就是:可以独立于类而存在,意思就是我们可以通过 类名::静态成员函数名 的方式来调用它,我相信还是能理解的,在c中我们说静态的数据存放在数据区,而局部的不是静态的变量则在栈中,一旦函数生命周期到了,那么局部的数据说不定咋变,所以我们能够访问数据区的数据,这是在编译完后就存放好的,而不是要运行时才产生的。

//当然还要注意写法,如果在类内部申明需要加static,然后在外部去定义的话那么static就不要去加了,这点注意就好了!

//至于“友元”,前面见识过了,后面还说了整个类可以是友元,该友元又称为友类;同时一个类的成员函数可以是另一个类的友元,即使把教师的职责的成员函数放到学生的类中,作为学生类的友元函数,这样可以访问学生的一切私有的数据了!



阅读(1486) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~