码迷,mamicode.com
首页 > 编程语言 > 详细

c++ private 继承

时间:2015-06-27 18:19:32      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:c++   指针   基类   

继承相关知识:

private继承对派生类不可见(exist but not accessable)

private 和protect 继承不允许基类指针指向派生类(编译error: ‘BaseClass‘ is an inaccessible base of ‘DerivedClass‘

  • reinterpret_cast可以将private继承的派生类指针强制转化为基类指针(通过pbase = static_cast <BaseClass*>(pdrived);但是不要这么做,因为违反了pravite inheritance的原则!(dynamic_cast 不行,有人说static_cast 也可以,但是我试了不行:gcc4.8.1,c++1)

pravite继承类似于(相似,有区别)在基类添加了一个private成员变量(composition)尊重原作,原文链接

//E.g., the “Car has-a Engine” relationship can be expressed using simple composition
class Engine {
public:
  Engine(int numCylinders);
  void start();                 // Starts this Engine
};
class Car {
public:
  Car() : e_(8) { }             // Initializes this Car with 8 cylinders
  void start() { e_.start(); }  // Start this Car by starting its Engine
private:
  Engine e_;                    // Car has-a Engine
};

//The “Car has-a Engine” relationship can also be expressed using private inheritance:
class Car : private Engine {    // Car has-a Engine
public:
  Car() : Engine(8) { }         // Initializes this Car with 8 cylinders
  using Engine::start;          // Start this Car by starting its Engine
};

//使用 composition 还是 private inheritance?
//Use composition when you can, private inheritance when you have to
//"Isa" relationship should be modelled by inheritance, "has-a" should be modelled by containment:
class B : public A     // B "is-a" A 
{ 
  ... 
} 

class B 
{ 
  ... 
  private: 
    A a_;     // B "has-a" A 
} 
//While public inheritence model an "is-a" relationship, private inheritance doesn‘t model anything at all, and is purely an implementation construct for sharing code with the class being inherited. This is better achieved by containment.

There are several similarities between these two variants:

In both cases there is exactly one Engine member object contained in every Car object
In neither case can users (outsiders) convert a Car* to an Engine*
In both cases the Car class has a start() method that calls the >start() method on the contained Engine object.

There are also several distinctions:

The simple-composition variant is needed if you want to contain several Engines per Car
The private-inheritance variant can introduce unnecessary multiple inheritance
The private-inheritance variant allows members of Car to convert a Car* to an Engine*
The private-inheritance variant allows access to the protected members of the base class
The private-inheritance variant allows Car to override Engine’s virtual functions
The private-inheritance variant makes it slightly simpler (20 characters compared to 28 characters) to give Car a start() method that simply calls through to the Engine’s start() method
Note that private inheritance is usually used to gain access into the protected members of the base class, but this is usually a short-term solution。
- Or A member (either data member or member function) declared in a protected section of a class can only be accessed by member functions and friends of that class, and by member functions and friends of derived classes,这就是为什么private继承可以访问protected的基类成员).


&ojb = class中的this指针,派生类指针转基类指针example:原文链接

class Animal { /* Some virtual members */ }
class Dog: public Animal {};
class Cat: public Animal {};


Dog     dog;
Cat     cat;
Animal& AnimalRef1 = dog;  // Notice no cast required. (Dogs and cats are animals).
Animal& AnimalRef2 = cat;
Animal* AnimalPtr1 = &dog;
Animal* AnimlaPtr2 = &cat;

Cat&    catRef1 = dynamic_cast<Cat&>(AnimalRef1);  // Throws an exception  AnimalRef1 is a dog
Cat*    catPtr1 = dynamic_cast<Cat*>(AnimalPtr1);  // Returns NULL         AnimalPtr1 is a dog
Cat&    catRef2 = dynamic_cast<Cat&>(AnimalRed2);  // Works
Cat*    catPtr2 = dynamic_cast<Cat*>(AnimalPtr2);  // Works

// This on the other hand makes no sense
// An animal object is not a cat. Therefore it can not be treated like a Cat.
Animal  a;
Cat&    catRef1 = dynamic_cast<Cat&>(a);    // Throws an exception  Its not a CAT
Cat*    catPtr1 = dynamic_cast<Cat*>(&a);   // Returns NULL         Its not a CAT.

大多数情况下,如果需要使用继承属性,则将数据定义为private,并且提供protected的接口,这样派生类可以定义自己的私有数据并且不会与基类的数据冲突,而且可以访问到基类的数据,更重要的是,在以后你需要对基类数据成员进行修改的时候不会使得派生类出错,这样可以最大化代码复用(只要不改变protected接口)。如果代码比较少,但是需要用到继承属性,可以定义少量protected数据,这样就是省去了定义一堆接口,简化代码。


要点:

虚析构函数:基类的析构函数必须是虚函数,防止内存泄露(slicing) ——make your destructor virtual if your class has any virtual functions(只要有虚函数)。Had Base’s destructor not been virtual, Derived’s destructor would not have been called – with likely bad effects, such as resources owned by Derived not being freed.

在设计函数的时候Pass-by-value should be avoided for objects:

myMethod (const SomeClass &object)  // good
myMethod (SomeClass object)         // bad: don‘t do this
  • 效率问题
  • objects passed by value through a base-class variable will in effect behave as a base-class object without the extended information defined by the derived class,如果参数是基类,则派生类会被截断。

Interface: A class with no data and where all functions are pure virtual functions(一般为public) is often called an interface.

纯虚函数的实现 派生类必须重新定义纯虚函数,但是有些共性的代码可以在纯虚函数中的实现完成,例如,可以用来执行某些具有共性的缺省设置,在派生类中显式执行BaseClass::pure_virtual_func即可;缺省设置也可以通过在基类中定义protected的成员函数,然后派生来能够在其成员函数中调用基类的protected函数来完成缺省设置。

派生类调用基类函数

void Der::f()
{
  Base::f();  // Or, if you prefer, this->Base::f();
}


Virtual Constructor? 就是纯虚函数的 clone(复制) 和 create(构造),但是在派生来中返回的为派生类的指针,而不是基类指针。That’s how to define a copy constructor or assignment operator for a class that contains a pointer to a (abstract) base class:

class Shape {
public:
  virtual ~Shape() { }                 // A virtual destructor
  virtual void draw() = 0;             // A pure virtual function
  virtual void move() = 0;
  // ...
  virtual Shape* clone()  const = 0;   // Uses the copy constructor
  virtual Shape* create() const = 0;   // Uses the default constructor
};
class Circle : public Shape {
public:
  Circle* clone()  const;   // Covariant Return Types; see below
  Circle* create() const;   // Covariant Return Types; see below
  // ...
};
Circle* Circle::clone()  const { return new Circle(*this); }
Circle* Circle::create() const { return new Circle();      }

Never hide member functions that were public in my base class

C++ can’t distinguish between a pointer-to-a-thing and a pointer-to-an-array-of-things

class Base {
public:
  virtual void f(); 
};
class Derived : public Base {
public:
  // ...
private:
  int i_;
};
void userCode(Base* arrayOfBase)
{
  arrayOfBase[1].f();           // 此处如果传进来的是派生类,则编译器会按照基类的大小去在数组中找索引为1的指针,runtime error!使用std::array<Derived, 10> 能在编译的时候报错,而不是运行时出错
}
int main()
{
  Derived arrayOfDerived[10];
  userCode(arrayOfDerived);
  // ...
}

to be continued….

c++ private 继承

标签:c++   指针   基类   

原文地址:http://blog.csdn.net/gw569453350game/article/details/46662723

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!