赞
踩
调用成员函数时,成员函数通过一个名为 this 的隐式参数来访问调用它的那个对象,用请求该函数的对象地址初始化 this ,this 的指向总是自己这个对象,所以 this 是一个常量指针
Box* get_address() //得到this的地址
{
return this;
}
Box* get_address() //得到this的地址
{
Box box;
this = &box; // error: lvalue required as left operand of assignment
return this;
}
#include <iostream> #include <cmath> using namespace std; class MyInteger { public: MyInteger() { this->num_ = 0; } MyInteger(int num) : num_(num) {} MyInteger operator+(const MyInteger &other) { MyInteger temp; temp.num_ = this->num_ + other.num_; // this->num_ += m.num_; // 这违反了加法运算符的语义,加法运算通常是创建一个新的对象来保存结果,而不是改变原始对象。 return temp; } MyInteger operator+(const int &other) // 运算符重载 { MyInteger temp; temp.num_ = this->num_ + other; return temp; } MyInteger operator+=(const MyInteger &other) { MyInteger temp; temp.num_ = this->num_ + other.num_; return temp; } MyInteger operator+=(const int &other) { MyInteger temp; temp.num_ = this->num_ + other; return temp; } MyInteger &operator++() { ++num_; return *this; } MyInteger operator++(int) { MyInteger temp(*this); num_++; return temp; } MyInteger &operator=(const MyInteger &myInteger) // 注意深浅拷贝问题 { num_ = myInteger.num_; } friend ostream &operator<<(ostream &out, const MyInteger &myInteger); // 重载左移运算符 没加 const ,cout << m++;报错 private: int num_; }; ostream &operator<<(ostream &out, const MyInteger &myInteger) { out << myInteger.num_; return out; } void test01() { MyInteger m; MyInteger m1(10); m1 = m + m1; cout << m << endl; cout << m1 << endl; } void test02() { MyInteger m(1); MyInteger m1(100); m = m1 + m; m1 += 10; cout << m << " " << m1 << endl; } void test03() { MyInteger m(2); MyInteger m1(8); // cout << ++(++m) << " " << ++m1 << endl; // cout << m << " "; cout << m++; cout << m; } int main() { // test01(); // test02(); test03(); // int a=1; // int b=2; // a=a+b; // cout<<a<<" "<<b<<endl; int c = 1; cout << endl; cout << c++ << endl; cout << c << endl; return 0; }
.,:: ,?:,sizeof,typeid,.* 这几个运算符不能被重载
1、构造函数
2、析构函数
3、拷贝构造函数
4、operator= 函数
多态实现的前提三个条件
1、必须是共有继承
2、通过基类指针指向派生类,并且访问派生类重写的方法。
3、基类中的被重写的方法是虚函数
这种技术让父类指针有多种形态,是一种泛型技术,直到运行时才决定执行哪个版本的函数。所谓泛型技术,就是使用不变的代码来实现可变的算法。多态中没有重写的函数是没有意义的。
水能载舟,亦能覆舟。多态也涉及了安全性的问题,
首先是无法访问子类中自己的虚函数,如Base * base=new Derived(); base->f1();
编译时不会通过的(其中f1()是子类自己的虚函数,父类没有);
然后是如果父类中虚函数是private或者protected,这些函数依旧会存在于虚函数表中,可以通过多态的方式来访问。
#include <iostream> using namespace std; class Father { public: virtual void f(){ cout<<"hello Father!"<<endl; } }; class Son : public Father { public: void f(){ cout << "hello Son!"<<endl; } }; int main() { Son s; Father *p = &s; p->f(); Father f; p=&f; p->f(); return 0; }
继承关系画成图像一个菱形,所以就叫做菱形继承,采用虚继承来解决二义性问题。
总的来说是为了避免内存泄漏,当子类中有指针成员变量时才会使用到。也就是说,虚析构函数使得删除指向子类的父类指针时,不仅可以调用父类的的析构函数,也会调用子类的析构函数,这样就可以释放子类指针成员变量在堆中的内存,达到防止内存泄漏的目的。
#include <bits/stdc++.h> using namespace std; class CA { public: CA() { cout << "CA" << endl; } virtual void f1() { cout << "CA::f1( )" << endl; // f2(); } void f2() { cout << "CA::f2( )" << endl; } virtual ~CA() { cout << "~CA" << endl; } }; class CB : public CA { public: CB() { cout << "CB" << endl; } virtual void f1() { cout << "CB::f1( )" << endl; } void f2() { cout << "CB::f2( )" << endl; } virtual ~CB() { cout << "~CB" << endl; } }; class CC : public CB { public: CC() { cout << "CC" << endl; } void f1() { cout<<"CC:f1()"<<endl; } void f2() { cout << "CC:f2()" << endl; } virtual ~CC() { cout << "~CC" << endl; } }; int main() { CA *pA = new CC(); pA->f1(); delete pA; CA *pA1 = new CB(); pA1->f1(); delete pA; return 0; }//注意看构造和析构的顺序,正好是相反的
面试的时候,问到了gcc和g++的区别,没答上来:
首先说明:gcc 和 GCC 是两个不同的东西
GCC:GNU Compiler Collection(GNU 编译器集合),它可以编译C、C++、JAV、Fortran、Pascal、Object-C、Ada等语言。
gcc是GCC中的GNU C Compiler(C 编译器)
g++是GCC中的GNU C++ Compiler(C++编译器)
一个有趣的事实就是,就本质而言,gcc和g++并不是编译器,也不是编译器的集合,它们只是一种驱动器,根据参数中要编译的文件的类型,调用对应的GUN编译器而已,比如,用gcc编译一个c文件的话,会有以下几个步骤:
Step1:Call a preprocessor, like cpp.
Step2:Call an actual compiler, like cc or cc1.
Step3:Call an assembler, like as.
Step4:Call a linker, like ld
由于编译器是可以更换的,所以gcc不仅仅可以编译C文件
所以,更准确的说法是:gcc调用了C compiler,而g++调用了C++ compiler
gcc和g++的主要区别:
对于 .c和.cpp文件,gcc分别当做c和cpp文件编译(c和cpp的语法强度是不一样的)
对于 .c和.cpp文件,g++则统一当做cpp文件编译
使用g++编译文件时,g++会自动链接标准库STL,而gcc不会自动链接STL
gcc在编译C文件时,可使用的预定义宏是比较少的
gcc在编译cpp文件时/g++在编译c文件和cpp文件时(这时候gcc和g++调用的都是cpp文件的编译器)
一般是加快程序执行速度,可能减小可执行文件大小,可能增加可执行文件大小。
速度快:当函数体较短时,内敛函数会像宏一样展开,所以执行速度比一般函数要快。但是如果函数体过大,一般的编译器会放弃内联方式,意思就是你使用内联函数,只不过是向编译器提出了一个申请,编译器可以拒绝,这个函数又会像普通函数一样,执行效率也和普通函数一样。
减小可执行文件大小:内联函数适度
增加可执行文件大小:内联函数过多
在c++中仿函数(Functor)是一个类或者结构体,重载了函数调用运算符()
,它的主要作用是提供一种更加灵活的函数对象,它可以包含状态信息,并且可以被传递给算法或者函数,从而实现定制的行为。比如实现排序准则、查找准则、谓词(就是一个bool返回值的函数)
#include <iostream> #include <vector> #include <algorithm> using namespace std; void Print(int val){cout<<val<<" ";} class Print1 { public: void operator()(int val){cout<<val<<" ";} }; void test01() { vector<int> v; v.push_back(6); v.push_back(66); for_each(v.begin(), v.end(), Print1()); cout<<endl<<"--------------"<<endl; for_each(v.begin(), v.end(), Print); } int main() { test01(); return 0; }
pointer-like-class
是指类似指针的类,这种类一般用来模拟指针的行为,但是与裸指针相比具有更多的功能和安全性,如智能指针(Smart Pointers)、迭代器(Iterators)。Smart Pointers有std::unique_ptr
和std::shared_ptr
、std::weak_ptr
。
判断奇数还是偶数
int a=11;
int b=1;
if(b&a){
cout << "is odd" <<endl;
}else{
cout<< "is even" <<endl;
}
取出指定的位
int a=0b11101101;
int b=0b1111;
cout << bitset<sizeof(char)*8>(a&b)<<endl;
判断是否为2的整数幂(0b10 0000 & 0b01 1111),结果是0,说明是2的整数幂。
int x = 64;
int y = x - 1;
cout << ((x & y) ? "no" : "yes") << endl;
a是一个指向含有三个int型数据数组的指针(如有int p[3]; a指向p是可以的 )
a1是一个函数三个int*型数据的数组(如a1可以初始化为{&b, &c, &d});
#include <iostream> #include <typeinfo> using namespace std; #define sz(type) cout<<sizeof(type)<<endl; int main(){ int b=10, c=1, d=2; int (*a)[3]; int* a1[3]; cout<<typeid(a).name()<<endl; sz(a); sz(a1); sz(a1[0]); sz(*a) sz(a[0][0]) return 0; }
1、初始化,定义引用时需要加&,
int a=1;
int &b=a;//相当于给a取了一个别名
2、作为函数参数传递,c++在函数参数中传递数组时,直接变成了指针,因为如果将数组传递过去需要将值一个一个拷贝过去,增加了函数调用的开销,所以在 C++ 中,我们有了一种比指针更加便捷的传递聚合类型数据的方式,那就是引用(Reference),通过这种方式传过去减少了生成副本的消耗。
void swap(int &a, int &b){
int temp=a;
a=b;
b=temp;
}
3、作为函数返回值来传递,例如重载左移运算符,需要输出多个内容就需要返回引用。
#include <iostream> #include <typeinfo> using namespace std; #define sz(type) cout << sizeof(type) << endl; int function1(int &aa) // 以返回值的方法返回函数值 { return aa; } int &function2(int &aa) // 以引用方式返回函数值 { return aa; } int main() { int a = 10; // 第一种情况,系统生成要返回值的副本(即临时变量) int b = function1(a); // function1()的返回值先储存在一个a的副本中, // 然后再把副本赋值给b // 第二种情况,报错 // function1(a) = 20;// function1()的返回值为临时变量,不能赋值(即不能为左值) // 第三种情况,系统不会生成返回值的副本 function2(a) = 20; // OK 此时a的值变成了20 cout<<a<<endl; }
重载左移运算符,返回引用才会连续输出两个值;
#include <iostream> using namespace std; class Point { public: int x_, y_; Point(int x, int y) : x_(x), y_(y) {} friend ostream &operator<<(ostream &os, const Point &p) { os << p.x_ << " " << p.y_ << endl; return os; } }; int main() { Point p(1, 2); cout<<p<<p; return 0; }
c++的内存主要分为一下几个部分:栈区、堆区、全局区(静态区)、文字常量区、程序代码区。
全局变量
存储在静态内存分配区,整个程序的生命周期都可以使用,其他文件使用关键字extern也可以使用
局部变量
存储在栈区,与函数共存亡
全局静态变量
与全局变量类似,也是存储在静态内存分配区,生命周期与整个程序同在,不过不能再其他文件使用。
局部静态变量
也是存储在静态内存分配区,调用函数后便一直存在,只不过只能在函数内可见。
1、别名:typedef、using
2、推断:auto、decltype
vector:视作可变大小的数组,可随机访问,在非尾部的位置插入比较慢
deque:双端队列,支持随机访问,在头尾位置插入和删除比较快
list:双向链表,支持双向顺序访问(rbegin()、rend()),在 list 任意位置插入和删除都比较快
forward_list:单向链表,只能单向顺序访问,在 forward_list 的任意位置插入和删除都比较快
array:固定大小的数组,支持随机访问,不能添加或者删除元素
string:与 vector 类似,专门保存字符串,随机访问快,在尾部插入和删除快
map:键值对,一对一,基于红黑树,对关键字进行排序
set:只保存关键字,不重复
multimap:关键字可以重复的 map ,即一对多,如统计数学课的学生成绩
multiset:保存可以重复的关键字
unordered_map:键值对,一对一,基于哈希值,不对键值对进行排序
unordered_set:只保存关键字,不排序
unordered_multimap:键值对,一对多,基于哈希值
unordered_multiset:保存可以重复的关键字,不排序
包括:stack、queue、priority_queue
stack 和 queue 基于deque实现, priority_queue 基于 vector 实现
包括输入流对象(ostream,如std::cin,从键盘读取数据),输出流对象(istream,如std::cout,向屏幕写入数据)
还有文件输入流对象(ifstream,使用 std::ifstream 来创建对象,将数据从文件中读取出来),文件输出流对象(ofstream,使用 std::ofstream 来创建对象,将数据写入文件)
#include <iostream> #include <fstream> using namespace std; void test01() { ofstream file; file.open("text.txt", ios::out); file << "xinm" << endl; file << "namji" << endl; file.close(); } void test02() { ifstream ifile; ifile.open("text.txt", ios::in); if(ifile.is_open()){ char buf[1024]; while(ifile >> buf) { cout<< buf<<endl; } } ifile.close(); } int main() { test02(); return 0; }
使用二进制流读写文件
#include <iostream> #include <fstream> using namespace std; class Person { public: // Person(char name[], int age):name_(name), age_(age){} char name_[20]; int age_; }; void test01() { ofstream file; file.open("text.txt", ios::out | ios::binary); Person p = {"hhhhh", 18}; file.write((const char *)&p, sizeof(p)); file.close(); } void test02() { ifstream ifile; ifile.open("text.txt", ios::in | ios::binary); if (ifile.is_open()) { // 1 // char buf[1024]; // while(ifile >> buf) // { // cout<< buf<<endl; // } // 2 // char buf[1024]; // while (ifile.getline(buf, sizeof(buf))) // { // cout << buf << endl; // } // 3 // string buf; // while(getline(ifile, buf)){ // cout << buf <<endl; // } Person p; ifile.read((char *)&p, sizeof(p)); cout << p.name_ << p.age_ << endl; } ifile.close(); } int main() { test02(); return 0; }
若在 try 中抛出异常,在转到 catch 前,会对有关对象进行析构
#include <iostream> using namespace std; //异常处理的构造和析构函数 class Student{ private: string name; int sno; public: Student(string name1,int sno1) { name=name1; sno=sno1; } ~Student() { cout<<"Destruct Student:"<<sno<<endl; } void checkSno() { if(sno==0) { throw sno; } else { cout<<name<<":"<<sno<<endl; } } }; int main() { try { Student a("pink",1); a.checkSno(); Student b("floyd",0); //构造对象 b.checkSno(); //抛出异常跳到catch语句块中 } catch(int) { cout<<"error:sno=0!"<<endl; } return 0; }
可以看到上面这段代码的输出结果是先对a、b析构然后再转到catch输出内容。
要注意继承的时候要加上基类的类型
#include <iostream> using namespace std; template<class T> class Base { public: T c; }; template<class T> class Deri: public Base<T> { public: T a; }; int main() { Deri<int> d; d.a=4; d.c=6; cout <<d.Base::c<<endl; // cout << sizeof(Deri<int>)<<endl; return 0; }
包括:构造函数、拷贝构造函数、析构函数,注意:operator=函数是可以被继承的
#include <iostream> #include <cstring> using namespace std; class A{ public: A(){ } A(int price, int weight):price_(price), weight_(weight){ } A& operator=(const A& a){ cout << "operator=1" << endl; } private: int price_; int weight_; }; class B: public A{ public: B(int price, int weight):price_(price), weight_(weight){ } private: int price_; int weight_; }; int main(){ // A a1(1,0); // A a2; // a2=a1; B b1(10,0),b2(2,0); b2=b1; return 0; }
上面说明operator=函数被继承下去了。
类内定义,类外初始化一次,然后在整个程序运行期间都可以存在
原因
1、静态成员变量存储在静态存储区域内,在编译阶段就为他们分配内存空间,
2、静态成员变量是类级别的,他在所有类实例中是公有的,如果允许在类内部初始化,就可能导致每个实例都有一个独立的副本
3、这样可以避免多次初始化
#include <iostream> #include <cstdlib> #include <ctime> #include <vector> #include <math.h> using namespace std; class Point { public: Point(int x, int y) : x_(x), y_(y) { } void setX(int val) { x_ = val; } void setY(int val) { y_ = val; } int getX() const { return x_; } int getY() const { return y_; } private: int x_; int y_; }; class Circle { public: Circle(int x, int y, int r) : center_(x, y), r_(r) { num_++; cout << "Circle number: " << getNum() << endl; ; } static int getNum() { return num_; } friend double getDistance(const Circle &c1, const Circle &c2); private: static int num_; Point center_; int r_; }; int Circle::num_ = 0; double getDistance(const Circle &c1, const Circle &c2) { double x=double(c2.center_.getX()-c1.center_.getX()); double y=double(c2.center_.getY()-c1.center_.getY()); return sqrt(x*x + y*y); } void testCircle() { Circle c1(1, 2, 3); Circle c2(4, 6, 2); cout << getDistance(c1, c2) << endl; } int main() { testCircle(); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。