c++面向对象
重载4个辨识
函数名
函数形参表
类的名称
成员函数的const属性
函数指针
#include <iostream>
#include <vector>
#include <string>
using namespace std;
bool (*cmp)(int x,int y);
bool ls(int x,int y){
cout<<(x > y)<<endl;
}
int main(){
int a = 3,b = 4;
cmp = &ls;
cmp(a,b);
*cmp;
}
this指针一般用于解决重名问题和返回自身的值或者引用。例如:
struct A{
int a;
void test(int a){
this->a = a;
}
普通对象可以调用const函数,也可以调用非const函数,但是const对象只能调用const函数。
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
class Person{
public :
Person(){
}
Person(int id,string name,int age):_id(id),_name(name),_age(age){
}
Person& set(int id,string name,int age){
_id = id;
_name = name;
_age = age;
return *this;
}
void print(ostream &os){
os<<_id<<endl;
os<<_name<<endl;
os<<_age<<endl;
}
void operator=( Person &p1){
p1._age = _age;
p1._name = _name;
p1._id = _id;
}
private:
int _id;
string _name;
int _age;
};
class A{
public:
A(){
_count++;
}
~A(){
--_count;
}
static int sum(){
return _count;
}
private:
static int _count ;
};
int A::_count = 0;
int main(){
A a;
A b;
A c;
cout<<A::sum()<<endl;
a.~A();
b.~A();
cout<<A::sum()<<endl;
}
const成员函数和普通函数可以构成重载
在有些时候我们必须使用初始化列表:
没有默认构造函数的类成员
const成员
引用类型的成员
有的类成员需要显式调用含参数的构造函数
为了防止隐式类型转换用explicit 加在构造函数前面
最后记住: 构造函数不能为const。
单例模式(把赋值和复制定义为私有)
如果你有一个带有虚函数功能的类,则它需要一个虚的析构函数,
1.如果一个类有虚函数功能,它经常作为一个基类使用
2.如果它是一个基类,它的派生类经常使用new来分配
3.如果一个派生类的对象使用new来分配,并且通过一个指向它的基类指针来控制,那么它经常通过一个指向它的基类指针来删除它。
const三种用法:
修饰形参:使得形参只读,不可被更改。
修饰返回值,禁止外界修改返回值。
修饰类的成员函数,禁止在函数体内修改本对象。
const是种常量语义(semantics),或者保护语义,而非const是一种修改语
如果要使用不在同一文件的变量,那个变量在那个文件中要被声明为static
C++ 之继承
这里我们总结下三种访问权限:
假设有有base类和derived类(public继承):
private成员作用域仅限于base内部
public成员作用域在所有位置
protected成员作用在base和derived内部
我们这里采用的继承方式为public继承,如果一个类里面有public、private、protected成员,他们经过public继承,在派生类中的访问标号为:public、不可访问、protected。
总结起来就是:
Private为个人日记,在派生类中无法被访问
Protected为家族秘籍,在派生类家族体系中可以访问
Public为完全公开的东西,在派生类中可以随意的访问
Private在派生类的内部不可见,但是通过基类本身的函数可以间接访问
这就说明了被派生类隐藏的函数可以通过指定基类的类名来调用。
子类可以正常调用从父类继承而来的函数
子类编写的函数,仍可以正常使用(包括构造函数)
通过子类Studnet s调用的默认是子类自己的版本,此时如果不显示的调用基类,编译会报错
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Person{
public:
Person(){}
Person(int id,
const string &name,
int age)
:id_(id),
name_(name),
age_(age)
{}
void set(int id,
const string &name,
int age)
{
id_ = id;
name_ = name;
age_ = age;
}
void print() const
{
cout << id_ << " " << name_ << " " << age_ << endl;
}
protected:
int id_;
string name_;
int age_;
};
class Student : public Person
{
private:
string school_;
public:
void set(int id,
const string &name,
int age,
const string &school)
{
id_ = id;
name_ = name;
age_ = age;
school_ = school;
}
void print() const
{
cout << id_ << " " << name_
<< " " << age_ << " "
<< school_ << endl;
}
};
class Programmer : public Person
{
private:
string language_;
};
int main(int argc, const char *argv[])
{
Student s;
//这里调用的是3个参数的版本,是否会结合到父类的set函数
S.set(12,“zhangsan”,23);//编译出错
s.Person::set(12, "zhangsan", 23);
s.print();
return 0;
}
C++之复制控制
复制和赋值,深拷贝和浅拷贝,深拷贝是拷贝指针指向的内存,即从新开辟一块空间。
禁止复制和赋值
#include <iostream>
#include <string>
#include <vector>
using namespace std;
/*
* 凡是继承该类的对象,均不可复制和赋值
*
*/
class NonCopyable
{
public:
NonCopyable() {};
~NonCopyable() {};
private:
NonCopyable(const NonCopyable &);
void operator=(const NonCopyable &);
};
//这里注意采用私有继承
class Test : private NonCopyable
{
};
int main(int argc, const char *argv[])
{
Test t;
Test t2(t);
Test t3;
t3 = t;
return 0;
} //编译出错
子类对象赋值给父类对象,对象会切除
Person p1;
Student s1;
s1.set(123, "zhangsan", 45, "longhua");
s1.print();
p1 = s1;//
p1.print();
输出:
123 zhangsan 45 longhua
123 zhangsan 45
基类的指针可以指向派生类,会丢失派生类的部分,例:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Animal
{
public:
void display()
{
cout << "In Animal " << endl;
}
};
class Cat : public Animal
{
public:
void display()
{
cout << "In Cat " << endl;
}
};
class Dog : public Animal
{
public:
void display()
{
cout << "In Dog " << endl;
}
};
int main(int argc, const char *argv[])
{
Animal *pa;
Cat c;
Dog d;
pa = &c;
pa->display(); // Animal
pa = &d;
pa->display(); // Animal
return 0;
}
如果是虚函数则调用的是派生类的函数,这其实是一种动态绑定,俗称多态
派生类的指针可以直接转化为基类的指针;基类指针转化为派生类的指针是不妥当的
class Animal
{
public:
virtual void display() //虚函数
{
cout << "In Animal " << endl;
}
};
int main(int argc, const char *argv[])
{
Animal *pa;
Cat c;
Dog d;
pa = &c;
pa->display(); // Cat
pa = &d;
pa->display(); // Dog
return 0;
}
如果用基类的指针指向一个派生类的对象,析构时要把派生类的析构函数设为虚函数,否则派生类的对象没有delete。
类的大小和的成员变量有关,如果类中只有方法则类的大小为1
纯虚函数,又叫抽象类,类似java中的接口
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//这个类叫做抽象类
class Animal
{
public:
//纯虚函数
virtual void run() = 0;
};
int main(int argc, const char *argv[])
{
Animal a;
return 0;
}
句柄类和智能指针
将指向派生类的指针放入一个类,该类的不同对象触发多态。句柄类需要重载->操作符。和句柄类类似智能指针重载了->和*操作符,更像是对一个类进行了再次封装,为了更好的管理内存,一般用于那些含有指针作为属性的类
句柄例:
class Animal{
public :
virtual ~Animal(){};
virtual void display() const = 0;
virtual Animal *copy() const = 0;
};
class Cat : public Animal{
public:
void display()const{
cout<<"I am cat"<<endl;
}
Cat *copy() const{
return new Cat(*this);// 返回指针的地址 ,操作对象的指针
}
};
class Dog:public Animal{
public:
void display()const {
cout<<"I am dog"<<endl;
}
Dog *copy() const {
return new Dog(*this);
}
};
class Bear:public Animal{
public:
void display()const {
cout<<"I am Bear"<<endl;
}
Bear *copy() const{
return new Bear(*this);
}
};
class Handle{
public:
Handle();
Handle(const Handle &a);
Handle(const Animal &a);
~Handle();
Handle &operator=(Handle &a);
Animal *operator->();
private:
Animal *str_;
};
#include "Handle.h"
Handle::Handle():str_(NULL){
}
Handle::Handle(const Handle &a):str_(a.str_->copy()){
}
Handle::Handle(const Animal &a):str_(a.copy()){
}
Animal *Handle::operator->(){
return str_;
}
Handle &Handle::operator=(Handle &a){
if(this != &a){ //地址和地址比较
delete str_;
str_ = a.str_->copy();
}
return *this;
}
Handle::~Handle(){
delete str_;
}
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。